// SPDX-License-Identifier: GPL-2.0
/*
 * drivers/video/rockchip/video/vehicle_cif.c
 *
 * mipi_dphy/csi_host/vicap driver for vehicle
 *
 * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
 * Authors:
 *	Jianwei Fan <jianwei.fan@rock-chips.com>
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/reset.h>

#include "vehicle-csi2-dphy-common.h"
#include "vehicle_cif.h"
#include "vehicle_flinger.h"
#include "vehicle_main.h"

#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <media/v4l2-mediabus.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <soc/rockchip/rockchip-system-status.h>
#include <linux/phy/phy.h>
#include <linux/uaccess.h>
#include <linux/bits.h>
#include "vehicle_samsung_dcphy_common.h"

#define CIF_DG VEHICLE_DG
#define CIF_ERR VEHICLE_DGERR

static struct vehicle_cif *g_cif;

#define write_reg(base, addr, val) \
	writel(val, (addr) + (base))
#define read_reg(base, addr) \
	readl((addr) + (base))

#define vehicle_write_csihost_reg(base, addr, val)  write_reg(base, addr, val)
#define vehicle_read_csihost_reg(base, addr) read_reg(base, addr)

//define cif clk and rst
static const char * const rk3568_cif_clks[] = {
	"aclk_cif",
	"hclk_cif",
	"dclk_cif",
	"iclk_cif_g",
};

static const char * const rk3568_cif_rsts[] = {
	"rst_cif_a",
	"rst_cif_h",
	"rst_cif_d",
	"rst_cif_p",
	"rst_cif_i",
};

static const char * const rk3588_cif_clks[] = {
	"aclk_cif",
	"hclk_cif",
	"dclk_cif",
};

static const char * const rk3588_cif_rsts[] = {
	"rst_cif_a",
	"rst_cif_h",
	"rst_cif_d",
};

static const char * const rk3562_cif_clks[] = {
	"aclk_cif",
	"hclk_cif",
	"dclk_cif",
	"csirx0_data",
	"csirx1_data",
	"csirx2_data",
	"csirx3_data",
};

static const char * const rk3562_cif_rsts[] = {
	"rst_cif_a",
	"rst_cif_h",
	"rst_cif_d",
	"rst_cif_i0",
	"rst_cif_i1",
	"rst_cif_i2",
	"rst_cif_i3",
};

static const char * const rk3576_cif_clks[] = {
	"aclk_cif",
	"hclk_cif",
	"dclk_cif",
	"i0clk_cif",
	"i1clk_cif",
	"i2clk_cif",
	"i3clk_cif",
	"i4clk_cif",
};

static const char * const rk3576_cif_rsts[] = {
	"rst_cif_a",
	"rst_cif_h",
	"rst_cif_d",
	"rst_cif_iclk0",
	"rst_cif_iclk1",
	"rst_cif_iclk2",
	"rst_cif_iclk3",
	"rst_cif_iclk4",
};

//define dphy and csi clks/rst
static struct clk_bulk_data rk3568_csi2_dphy_hw_clks[] = {
	{ .id = "pclk" },
};

static struct clk_bulk_data rk3568_csi2_clks[] = {
	{ .id = "pclk_csi2host" },
};

static const char * const rk3568_csi2_rsts[] = {
	"srst_csihost_p",
};

static struct clk_bulk_data rk3588_csi2_dphy_hw_clks[] = {
	{ .id = "pclk" },
};

static const char * const rk3588_csi2_dphy_hw_rsts[] = {
	"srst_csiphy",
	"srst_p_csiphy",
};

static struct clk_bulk_data rk3588_csi2_clks[] = {
	{ .id = "pclk_csi2host" },
};

static struct clk_bulk_data rk3588_csi2_dcphy_clks[] = {
	{ .id = "pclk_csi2host" },
	{ .id = "iclk_csi2host" },
};

static const char * const rk3588_csi2_rsts[] = {
	"srst_csihost_p",
	"srst_csihost_vicap",
};

static struct clk_bulk_data rk3562_csi2_dphy_hw_clks[] = {
	{ .id = "pclk" },
};

static const char * const rk3562_csi2_dphy_hw_rsts[] = {
	"srst_p_csiphy",
};

static struct clk_bulk_data rk3562_csi2_clks[] = {
	{ .id = "pclk_csi2host" },
};

static const char * const rk3562_csi2_rsts[] = {
	"srst_csihost_p",
};

static struct clk_bulk_data rk3576_csi2_dphy_hw_clks[] = {
	{ .id = "pclk" },
};

static const char * const rk3576_csi2_dphy_hw_rsts[] = {
	"srst_p_csiphy",
};

static struct clk_bulk_data rk3576_csi2_clks[] = {
	{ .id = "pclk_csi2host" },
};

static struct clk_bulk_data rk3576_csi2_dcphy_clks[] = {
	{ .id = "pclk_csi2host" },
	{ .id = "iclk_csi2host" },
};

static const char * const rk3576_csi2_rsts[] = {
	"srst_csihost_p",
};

//define cif regs
static const struct vehicle_cif_reg rk3568_cif_regs[] = {
	[CIF_REG_DVP_CTRL] = CIF_REG_NAME(CIF_CTRL, "CIF_REG_DVP_CTRL"),
	[CIF_REG_DVP_INTEN] = CIF_REG_NAME(CIF_INTEN, "CIF_REG_DVP_INTEN"),
	[CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(CIF_INTSTAT, "CIF_REG_DVP_INTSTAT"),
	[CIF_REG_DVP_FOR] = CIF_REG_NAME(CIF_FOR, "CIF_REG_DVP_FOR"),
	[CIF_REG_DVP_MULTI_ID] = CIF_REG_NAME(CIF_MULTI_ID, "CIF_REG_DVP_MULTI_ID"),
	[CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(CIF_FRM0_ADDR_Y, "CIF_REG_DVP_FRM0_ADDR_Y"),
	[CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(CIF_FRM0_ADDR_UV, "CIF_REG_DVP_FRM0_ADDR_UV"),
	[CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(CIF_FRM1_ADDR_Y, "CIF_REG_DVP_FRM1_ADDR_Y"),
	[CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(CIF_FRM1_ADDR_UV, "CIF_REG_DVP_FRM1_ADDR_UV"),
	[CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(CIF_VIR_LINE_WIDTH,
						"CIF_REG_DVP_VIR_LINE_WIDTH"),
	[CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(CIF_SET_SIZE, "CIF_REG_DVP_SET_SIZE"),
	[CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(CIF_LINE_INT_NUM, "CIF_REG_DVP_LINE_INT_NUM"),
	[CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(CIF_LINE_CNT, "CIF_REG_DVP_LINE_CNT"),
	[CIF_REG_DVP_CROP] = CIF_REG_NAME(RV1126_CIF_CROP, "CIF_REG_DVP_CROP"),
	[CIF_REG_DVP_FIFO_ENTRY] = CIF_REG_NAME(RK3568_CIF_FIFO_ENTRY, "CIF_REG_DVP_FIFO_ENTRY"),
	[CIF_REG_DVP_FRAME_STATUS] = CIF_REG_NAME(RV1126_CIF_FRAME_STATUS,
						"CIF_REG_DVP_FRAME_STATUS"),
	[CIF_REG_DVP_CUR_DST] = CIF_REG_NAME(RV1126_CIF_CUR_DST, "CIF_REG_DVP_CUR_DST"),
	[CIF_REG_DVP_LAST_LINE] = CIF_REG_NAME(RV1126_CIF_LAST_LINE, "CIF_REG_DVP_LAST_LINE"),
	[CIF_REG_DVP_LAST_PIX] = CIF_REG_NAME(RV1126_CIF_LAST_PIX, "CIF_REG_DVP_LAST_PIX"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID1,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID1"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID1,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID1"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID1,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID1"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID1,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID1"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID2,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID2"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID2,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID2"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID2,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID2"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID2,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID2"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID3,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID3"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID3,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID3"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID3,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID3"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID3,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CIF_CSI_ID0_CTRL0,
						"CIF_REG_MIPI_LVDS_ID0_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CIF_CSI_ID0_CTRL1,
						"CIF_REG_MIPI_LVDS_ID0_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CIF_CSI_ID1_CTRL0,
						"CIF_REG_MIPI_LVDS_ID1_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CIF_CSI_ID1_CTRL1,
						"CIF_REG_MIPI_LVDS_ID1_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CIF_CSI_ID2_CTRL0,
						"CIF_REG_MIPI_LVDS_ID2_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CIF_CSI_ID2_CTRL1,
						"CIF_REG_MIPI_LVDS_ID2_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CIF_CSI_ID3_CTRL0,
						"CIF_REG_MIPI_LVDS_ID3_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CIF_CSI_ID3_CTRL1,
						"CIF_REG_MIPI_LVDS_ID3_CTRL1"),
	[CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CIF_CSI_MIPI_LVDS_CTRL,
						"CIF_REG_MIPI_LVDS_CTRL"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3"),
	[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CIF_CSI_INTEN, "CIF_REG_MIPI_LVDS_INTEN"),
	[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CIF_CSI_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CIF_CSI_LINE_INT_NUM_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CIF_CSI_LINE_INT_NUM_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CIF_CSI_LINE_CNT_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CIF_CSI_LINE_CNT_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"),
	[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CIF_CSI_ID0_CROP_START,
						"CIF_REG_MIPI_LVDS_ID0_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CIF_CSI_ID1_CROP_START,
						"CIF_REG_MIPI_LVDS_ID1_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CIF_CSI_ID2_CROP_START,
						"CIF_REG_MIPI_LVDS_ID2_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CIF_CSI_ID3_CROP_START,
						"CIF_REG_MIPI_LVDS_ID3_CROP_START"),
	[CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC0,
						"CIF_REG_MIPI_FRAME_NUM_VC0"),
	[CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC1,
						"CIF_REG_MIPI_FRAME_NUM_VC1"),
	[CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC2,
						"CIF_REG_MIPI_FRAME_NUM_VC2"),
	[CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC3,
						"CIF_REG_MIPI_FRAME_NUM_VC3"),
	[CIF_REG_Y_STAT_CONTROL] = CIF_REG_NAME(CIF_Y_STAT_CONTROL,
						"CIF_REG_Y_STAT_CONTROL"),
	[CIF_REG_Y_STAT_VALUE] = CIF_REG_NAME(CIF_Y_STAT_VALUE, "CIF_REG_Y_STAT_VALUE"),
	[CIF_REG_MMU_DTE_ADDR] = CIF_REG_NAME(CIF_MMU_DTE_ADDR, "CIF_REG_MMU_DTE_ADDR"),
	[CIF_REG_MMU_STATUS] = CIF_REG_NAME(CIF_MMU_STATUS, "CIF_REG_MMU_STATUS"),
	[CIF_REG_MMU_COMMAND] = CIF_REG_NAME(CIF_MMU_COMMAND, "CIF_REG_MMU_COMMAND"),
	[CIF_REG_MMU_PAGE_FAULT_ADDR] = CIF_REG_NAME(CIF_MMU_PAGE_FAULT_ADDR,
						"CIF_REG_MMU_PAGE_FAULT_ADDR"),
	[CIF_REG_MMU_ZAP_ONE_LINE] = CIF_REG_NAME(CIF_MMU_ZAP_ONE_LINE, "CIF_REG_MMU_ZAP_ONE_LINE"),
	[CIF_REG_MMU_INT_RAWSTAT] = CIF_REG_NAME(CIF_MMU_INT_RAWSTAT, "CIF_REG_MMU_INT_RAWSTAT"),
	[CIF_REG_MMU_INT_CLEAR] = CIF_REG_NAME(CIF_MMU_INT_CLEAR, "CIF_REG_MMU_INT_CLEAR"),
	[CIF_REG_MMU_INT_MASK] = CIF_REG_NAME(CIF_MMU_INT_MASK, "CIF_REG_MMU_INT_MASK"),
	[CIF_REG_MMU_INT_STATUS] = CIF_REG_NAME(CIF_MMU_INT_STATUS, "CIF_REG_MMU_INT_STATUS"),
	[CIF_REG_MMU_AUTO_GATING] = CIF_REG_NAME(CIF_MMU_AUTO_GATING, "CIF_REG_MMU_AUTO_GATING"),
	[CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_VI_CON0, "CIF_REG_GRF_CIFIO_CON"),
	[CIF_REG_GRF_CIFIO_CON1] = CIF_REG_NAME(CIF_GRF_VI_CON1, "CIF_REG_GRF_CIFIO_CON1"),
};

static const struct vehicle_cif_reg rk3588_cif_regs[] = {
	[CIF_REG_DVP_CTRL] = CIF_REG_NAME(DVP_CTRL, "CIF_REG_DVP_CTRL"),
	[CIF_REG_DVP_INTEN] = CIF_REG_NAME(DVP_INTEN, "CIF_REG_DVP_INTEN"),
	[CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(DVP_INTSTAT, "CIF_REG_DVP_INTSTAT"),
	[CIF_REG_DVP_FOR] = CIF_REG_NAME(DVP_FOR, "CIF_REG_DVP_FOR"),
	[CIF_REG_DVP_MULTI_ID] = CIF_REG_NAME(DVP_MULTI_ID, "CIF_REG_DVP_MULTI_ID"),
	[CIF_REG_DVP_SAV_EAV] = CIF_REG_NAME(DVP_SAV_EAV, "CIF_REG_DVP_SAV_EAV"),
	[CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID0, "CIF_REG_DVP_FRM0_ADDR_Y"),
	[CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID0, "CIF_REG_DVP_FRM0_ADDR_UV"),
	[CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID0, "CIF_REG_DVP_FRM1_ADDR_Y"),
	[CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID0, "CIF_REG_DVP_FRM1_ADDR_UV"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID1,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID1"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID1,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID1"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID1,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID1"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID1,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID1"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID2,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID2"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID2,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID2"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID2,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID2"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID2,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID2"),
	[CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID3,
						"CIF_REG_DVP_FRM0_ADDR_Y_ID3"),
	[CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID3,
						"CIF_REG_DVP_FRM0_ADDR_UV_ID3"),
	[CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID3,
						"CIF_REG_DVP_FRM1_ADDR_Y_ID3"),
	[CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID3,
						"CIF_REG_DVP_FRM1_ADDR_UV_ID3"),
	[CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(DVP_VIR_LINE_WIDTH,
						"CIF_REG_DVP_VIR_LINE_WIDTH"),
	[CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(DVP_CROP_SIZE, "CIF_REG_DVP_SET_SIZE"),
	[CIF_REG_DVP_CROP] = CIF_REG_NAME(DVP_CROP, "CIF_REG_DVP_CROP"),
	[CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_INT_NUM"),
	[CIF_REG_DVP_LINE_INT_NUM1] = CIF_REG_NAME(DVP_LINE_INT_NUM_23,
						"CIF_REG_DVP_LINE_INT_NUM1"),
	[CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_CNT"),
	[CIF_REG_DVP_LINE_CNT1] = CIF_REG_NAME(DVP_LINE_INT_NUM_23, "CIF_REG_DVP_LINE_CNT1"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0,
						"CIF_REG_MIPI_LVDS_ID0_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1,
						"CIF_REG_MIPI_LVDS_ID0_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0,
						"CIF_REG_MIPI_LVDS_ID1_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1,
						"CIF_REG_MIPI_LVDS_ID1_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0,
						"CIF_REG_MIPI_LVDS_ID2_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1,
						"CIF_REG_MIPI_LVDS_ID2_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0,
						"CIF_REG_MIPI_LVDS_ID3_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1,
						"CIF_REG_MIPI_LVDS_ID3_CTRL1"),
	[CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"),
	[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"),
	[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"),
	[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START,
						"CIF_REG_MIPI_LVDS_ID0_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START,
						"CIF_REG_MIPI_LVDS_ID1_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START,
						"CIF_REG_MIPI_LVDS_ID2_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START,
						"CIF_REG_MIPI_LVDS_ID3_CROP_START"),
	[CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0,
						"CIF_REG_MIPI_FRAME_NUM_VC0"),
	[CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1,
						"CIF_REG_MIPI_FRAME_NUM_VC1"),
	[CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2,
						"CIF_REG_MIPI_FRAME_NUM_VC2"),
	[CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3,
						"CIF_REG_MIPI_FRAME_NUM_VC3"),
	[CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0,
						"CIF_REG_MIPI_EFFECT_CODE_ID0"),
	[CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1,
						"CIF_REG_MIPI_EFFECT_CODE_ID1"),
	[CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2,
						"CIF_REG_MIPI_EFFECT_CODE_ID2"),
	[CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3,
						"CIF_REG_MIPI_EFFECT_CODE_ID3"),
	[CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD, "CIF_REG_MIPI_ON_PAD"),
	[CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"),
	[CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"),
	[CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"),
	[CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"),
	[CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"),
	[CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0,
						"CIF_REG_SCL_FRM0_ADDR_CH0"),
	[CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0,
						"CIF_REG_SCL_FRM1_ADDR_CH0"),
	[CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"),
	[CIF_REG_SCL_FRM0_ADDR_CH1] = CIF_REG_NAME(SCL_FRM0_ADDR_CH1,
						"CIF_REG_SCL_FRM0_ADDR_CH1"),
	[CIF_REG_SCL_FRM1_ADDR_CH1] = CIF_REG_NAME(SCL_FRM1_ADDR_CH1,
						"CIF_REG_SCL_FRM1_ADDR_CH1"),
	[CIF_REG_SCL_VLW_CH1] = CIF_REG_NAME(SCL_VLW_CH1, "CIF_REG_SCL_VLW_CH1"),
	[CIF_REG_SCL_FRM0_ADDR_CH2] = CIF_REG_NAME(SCL_FRM0_ADDR_CH2,
						"CIF_REG_SCL_FRM0_ADDR_CH2"),
	[CIF_REG_SCL_FRM1_ADDR_CH2] = CIF_REG_NAME(SCL_FRM1_ADDR_CH2,
						"CIF_REG_SCL_FRM1_ADDR_CH2"),
	[CIF_REG_SCL_VLW_CH2] = CIF_REG_NAME(SCL_VLW_CH2, "CIF_REG_SCL_VLW_CH2"),
	[CIF_REG_SCL_FRM0_ADDR_CH3] = CIF_REG_NAME(SCL_FRM0_ADDR_CH3, "CIF_REG_SCL_FRM0_ADDR_CH3"),
	[CIF_REG_SCL_FRM1_ADDR_CH3] = CIF_REG_NAME(SCL_FRM1_ADDR_CH3, "CIF_REG_SCL_FRM1_ADDR_CH3"),
	[CIF_REG_SCL_VLW_CH3] = CIF_REG_NAME(SCL_VLW_CH3, "CIF_REG_SCL_VLW_CH3"),
	[CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"),
	[CIF_REG_SCL_BLC_CH1] = CIF_REG_NAME(SCL_BLC_CH1, "CIF_REG_SCL_BLC_CH1"),
	[CIF_REG_SCL_BLC_CH2] = CIF_REG_NAME(SCL_BLC_CH2, "CIF_REG_SCL_BLC_CH2"),
	[CIF_REG_SCL_BLC_CH3] = CIF_REG_NAME(SCL_BLC_CH3, "CIF_REG_SCL_BLC_CH3"),
	[CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"),
	[CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"),
	[CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"),
	[CIF_REG_TOISP1_CTRL] = CIF_REG_NAME(TOISP1_CH_CTRL, "CIF_REG_TOISP1_CTRL"),
	[CIF_REG_TOISP1_SIZE] = CIF_REG_NAME(TOISP1_CROP_SIZE, "CIF_REG_TOISP1_SIZE"),
	[CIF_REG_TOISP1_CROP] = CIF_REG_NAME(TOISP1_CROP, "CIF_REG_TOISP1_CROP"),
	[CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_SOC_CON2, "CIF_REG_GRF_CIFIO_CON"),
};

static const struct vehicle_cif_reg rk3562_cif_regs[] = {
	[CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0,
						"CIF_REG_MIPI_LVDS_ID0_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1,
						"CIF_REG_MIPI_LVDS_ID0_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0,
						"CIF_REG_MIPI_LVDS_ID1_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1,
						"CIF_REG_MIPI_LVDS_ID1_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0,
						"CIF_REG_MIPI_LVDS_ID2_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1,
						"CIF_REG_MIPI_LVDS_ID2_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0,
						"CIF_REG_MIPI_LVDS_ID3_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1,
						"CIF_REG_MIPI_LVDS_ID3_CTRL1"),
	[CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"),
	[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"),
	[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"),
	[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START,
						"CIF_REG_MIPI_LVDS_ID0_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START,
						"CIF_REG_MIPI_LVDS_ID1_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START,
						"CIF_REG_MIPI_LVDS_ID2_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START,
						"CIF_REG_MIPI_LVDS_ID3_CROP_START"),
	[CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0,
						"CIF_REG_MIPI_FRAME_NUM_VC0"),
	[CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1,
						"CIF_REG_MIPI_FRAME_NUM_VC1"),
	[CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2,
						"CIF_REG_MIPI_FRAME_NUM_VC2"),
	[CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3,
						"CIF_REG_MIPI_FRAME_NUM_VC3"),
	[CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0,
						"CIF_REG_MIPI_EFFECT_CODE_ID0"),
	[CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1,
						"CIF_REG_MIPI_EFFECT_CODE_ID1"),
	[CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2,
						"CIF_REG_MIPI_EFFECT_CODE_ID2"),
	[CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3,
						"CIF_REG_MIPI_EFFECT_CODE_ID3"),
	[CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD, "CIF_REG_MIPI_ON_PAD"),
	[CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"),
	[CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"),
	[CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"),
	[CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"),
	[CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"),
	[CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0,
						"CIF_REG_SCL_FRM0_ADDR_CH0"),
	[CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0,
						"CIF_REG_SCL_FRM1_ADDR_CH0"),
	[CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"),
	[CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"),
	[CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"),
	[CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"),
	[CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"),
};

static const struct vehicle_cif_reg rk3576_cif_regs[] = {
	[CIF_REG_DVP_CTRL] = CIF_REG_NAME(DVP_CTRL, "CIF_REG_DVP_CTRL"),
	[CIF_REG_DVP_INTEN] = CIF_REG_NAME(DVP_INTEN, "CIF_REG_DVP_INTEN"),
	[CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(DVP_INTSTAT, "CIF_REG_DVP_INTSTAT"),
	[CIF_REG_DVP_FOR] = CIF_REG_NAME(DVP_FOR, "CIF_REG_DVP_FOR"),
	[CIF_REG_DVP_SAV_EAV] = CIF_REG_NAME(DVP_SAV_EAV, "CIF_REG_DVP_SAV_EAV"),
	[CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID0, "CIF_REG_DVP_FRM0_ADDR_Y"),
	[CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID0, "CIF_REG_DVP_FRM0_ADDR_UV"),
	[CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID0, "CIF_REG_DVP_FRM1_ADDR_Y"),
	[CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID0, "CIF_REG_DVP_FRM1_ADDR_UV"),
	[CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(DVP_VIR_LINE_WIDTH,
						"CIF_REG_DVP_VIR_LINE_WIDTH"),
	[CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(DVP_CROP_SIZE, "CIF_REG_DVP_SET_SIZE"),
	[CIF_REG_DVP_CROP] = CIF_REG_NAME(DVP_CROP, "CIF_REG_DVP_CROP"),
	[CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_INT_NUM"),
	[CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(DVP_LINE_CNT_01, "CIF_REG_DVP_LINE_CNT"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0,
						"CIF_REG_MIPI_LVDS_ID0_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1,
						"CIF_REG_MIPI_LVDS_ID0_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0,
						"CIF_REG_MIPI_LVDS_ID1_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1,
						"CIF_REG_MIPI_LVDS_ID1_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0,
						"CIF_REG_MIPI_LVDS_ID2_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1,
						"CIF_REG_MIPI_LVDS_ID2_CTRL1"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0,
						"CIF_REG_MIPI_LVDS_ID3_CTRL0"),
	[CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1,
						"CIF_REG_MIPI_LVDS_ID3_CTRL1"),
	[CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3,
						"CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"),
	[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3,
						"CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"),
	[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"),
	[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1_RK3576,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3_RK3576,
						"CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1_RK3576,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"),
	[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3_RK3576,
						"CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"),
	[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START_RK3576,
						"CIF_REG_MIPI_LVDS_ID0_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START_RK3576,
						"CIF_REG_MIPI_LVDS_ID1_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START_RK3576,
						"CIF_REG_MIPI_LVDS_ID2_CROP_START"),
	[CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START_RK3576,
						"CIF_REG_MIPI_LVDS_ID3_CROP_START"),
	[CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0_RK3576,
						"CIF_REG_MIPI_FRAME_NUM_VC0"),
	[CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1_RK3576,
						"CIF_REG_MIPI_FRAME_NUM_VC1"),
	[CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2_RK3576,
						"CIF_REG_MIPI_FRAME_NUM_VC2"),
	[CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3_RK3576,
						"CIF_REG_MIPI_FRAME_NUM_VC3"),
	[CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0_RK3576,
						"CIF_REG_MIPI_EFFECT_CODE_ID0"),
	[CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1_RK3576,
						"CIF_REG_MIPI_EFFECT_CODE_ID1"),
	[CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2_RK3576,
						"CIF_REG_MIPI_EFFECT_CODE_ID2"),
	[CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3_RK3576,
						"CIF_REG_MIPI_EFFECT_CODE_ID3"),
	[CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD_RK3576, "CIF_REG_MIPI_ON_PAD"),
	[CIF_REG_MIPI_SET_SIZE_ID0] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID0_RK3576,
						"CIF_REG_MIPI_SET_SIZE_ID0"),
	[CIF_REG_MIPI_SET_SIZE_ID1] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID1_RK3576,
						"CIF_REG_MIPI_SET_SIZE_ID1"),
	[CIF_REG_MIPI_SET_SIZE_ID2] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID2_RK3576,
						"CIF_REG_MIPI_SET_SIZE_ID2"),
	[CIF_REG_MIPI_SET_SIZE_ID3] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID3_RK3576,
						"CIF_REG_MIPI_SET_SIZE_ID3"),
	[CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"),
	[CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"),
	[CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"),
	[CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"),
	[CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"),
	[CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0, "CIF_REG_SCL_FRM0_ADDR_CH0"),
	[CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0, "CIF_REG_SCL_FRM1_ADDR_CH0"),
	[CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"),
	[CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"),
	[CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"),
	[CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"),
	[CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"),
	[CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_IOC_MISC_CON1_RK3576,
							"CIF_REG_GRF_CIFIO_CON"),
};

//define dphy and csi regs
static const struct grf_reg rk3568_grf_dphy_regs[] = {
	[GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_VI_CON0, 4, 0),
	[GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_VI_CON0, 4, 4),
	[GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_VI_CON0, 1, 8),
	[GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_VI_CON0, 1, 9),
	[GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_VI_CON0, 1, 10),
	[GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_VI_CON0, 1, 11),
	[GRF_DPHY_ISP_CSI2PHY_SEL] = GRF_REG(GRF_VI_CON1, 1, 12),
	[GRF_DPHY_CIF_CSI2PHY_SEL] = GRF_REG(GRF_VI_CON1, 1, 11),
	[GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_VI_CON1, 1, 7),
};

static const struct csi2dphy_reg rk3568_csi2dphy_regs[] = {
	[CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE),
	[CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN),
	[CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE),
	[CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN),
	[CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE),
	[CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN),
	[CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE),
	[CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN),
	[CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE),
	[CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN),
	[CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE),
	[CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN),
	[CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE),
	[CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN),
};

static const struct grf_reg rk3588_grf_dphy_regs[] = {
	[GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_DPHY_CON0, 4, 0),
	[GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_DPHY_CON0, 4, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(GRF_DPHY_CON0, 2, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(GRF_DPHY_CON0, 2, 6),
	[GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_DPHY_CON0, 1, 8),
	[GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 9),
	[GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_DPHY_CON0, 1, 10),
	[GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 11),
	[GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_SOC_CON2, 1, 6),
	[GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(GRF_SOC_CON2, 1, 7),
	[GRF_DPHY_CSIHOST2_SEL] = GRF_REG(GRF_SOC_CON2, 1, 8),
	[GRF_DPHY_CSIHOST3_SEL] = GRF_REG(GRF_SOC_CON2, 1, 9),
	[GRF_DPHY_CSIHOST4_SEL] = GRF_REG(GRF_SOC_CON2, 1, 10),
	[GRF_DPHY_CSIHOST5_SEL] = GRF_REG(GRF_SOC_CON2, 1, 11),
};

static const struct csi2dphy_reg rk3588_csi2dphy_regs[] = {
	[CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE),
	[CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN),
	[CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE),
	[CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN),
	[CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE),
	[CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN),
	[CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE),
	[CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN),
	[CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE),
	[CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN),
	[CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE),
	[CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN),
	[CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE),
	[CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN),
	[CSI2PHY_CLK1_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_LANE_EN),
};

static const struct grf_reg rk3588_grf_dcphy_regs[] = {
	[GRF_CPHY_MODE] = GRF_REG(GRF_DCPHY_CON0, 9, 0),
};

static const struct csi2dphy_reg rk3588_csi2dcphy_regs[] = {
	[CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_WR_THS_SETTLE),
	[CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_THS_SETTLE),
	[CSI2PHY_LANE0_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC),
	[CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_THS_SETTLE),
	[CSI2PHY_LANE1_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC),
	[CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_THS_SETTLE),
	[CSI2PHY_LANE2_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC),
	[CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_THS_SETTLE),
	[CSI2PHY_LANE3_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC),
	[CSI2PHY_CLK_LANE_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_LANE_ENABLE),
	[CSI2PHY_DATA_LANE0_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE0_ENABLE),
	[CSI2PHY_DATA_LANE1_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE1_ENABLE),
	[CSI2PHY_DATA_LANE2_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE2_ENABLE),
	[CSI2PHY_DATA_LANE3_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE3_ENABLE),
	[CSI2PHY_S0C_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0C_GNR_CON1),
	[CSI2PHY_S0C_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON1),
	[CSI2PHY_S0C_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON2),
	[CSI2PHY_S0C_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON3),
	[CSI2PHY_COMBO_S0D0_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_GNR_CON1),
	[CSI2PHY_COMBO_S0D0_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON1),
	[CSI2PHY_COMBO_S0D0_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON2),
	[CSI2PHY_COMBO_S0D0_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON3),
	[CSI2PHY_COMBO_S0D0_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON6),
	[CSI2PHY_COMBO_S0D0_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON7),
	[CSI2PHY_COMBO_S0D0_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON0),
	[CSI2PHY_COMBO_S0D0_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON2),
	[CSI2PHY_COMBO_S0D0_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON4),
	[CSI2PHY_COMBO_S0D0_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_CRC_CON1),
	[CSI2PHY_COMBO_S0D0_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_CRC_CON2),
	[CSI2PHY_COMBO_S0D1_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_GNR_CON1),
	[CSI2PHY_COMBO_S0D1_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON1),
	[CSI2PHY_COMBO_S0D1_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON2),
	[CSI2PHY_COMBO_S0D1_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON3),
	[CSI2PHY_COMBO_S0D1_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON6),
	[CSI2PHY_COMBO_S0D1_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON7),
	[CSI2PHY_COMBO_S0D1_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON0),
	[CSI2PHY_COMBO_S0D1_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON2),
	[CSI2PHY_COMBO_S0D1_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON4),
	[CSI2PHY_COMBO_S0D1_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_CRC_CON1),
	[CSI2PHY_COMBO_S0D1_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_CRC_CON2),
	[CSI2PHY_COMBO_S0D2_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_GNR_CON1),
	[CSI2PHY_COMBO_S0D2_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON1),
	[CSI2PHY_COMBO_S0D2_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON2),
	[CSI2PHY_COMBO_S0D2_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON3),
	[CSI2PHY_COMBO_S0D2_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON6),
	[CSI2PHY_COMBO_S0D2_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON7),
	[CSI2PHY_COMBO_S0D2_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON0),
	[CSI2PHY_COMBO_S0D2_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON2),
	[CSI2PHY_COMBO_S0D2_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON4),
	[CSI2PHY_COMBO_S0D2_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_CRC_CON1),
	[CSI2PHY_COMBO_S0D2_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_CRC_CON2),
	[CSI2PHY_S0D3_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0D3_GNR_CON1),
	[CSI2PHY_S0D3_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON1),
	[CSI2PHY_S0D3_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON2),
	[CSI2PHY_S0D3_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON3),
	[CSI2PHY_S0D3_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON0),
	[CSI2PHY_S0D3_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON2),
	[CSI2PHY_S0D3_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON4),
};

static const struct grf_reg rk3562_grf_dphy_regs[] = {
	[GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(RK3562_GRF_VI_CON0, 4, 0),
	[GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(RK3562_GRF_VI_CON0, 4, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(RK3562_GRF_VI_CON0, 2, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(RK3562_GRF_VI_CON0, 2, 6),
	[GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(RK3562_GRF_VI_CON0, 1, 8),
	[GRF_DPHY_CLK_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 9),
	[GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(RK3562_GRF_VI_CON0, 1, 10),
	[GRF_DPHY_CLK1_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 11),
	[GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 12),
	[GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 13),
	[GRF_DPHY1_CSI2PHY_FORCERXMODE] = GRF_REG(RK3562_GRF_VI_CON1, 4, 0),
	[GRF_DPHY1_CSI2PHY_DATALANE_EN] = GRF_REG(RK3562_GRF_VI_CON1, 4, 4),
	[GRF_DPHY1_CSI2PHY_DATALANE_EN0] = GRF_REG(RK3562_GRF_VI_CON1, 2, 4),
	[GRF_DPHY1_CSI2PHY_DATALANE_EN1] = GRF_REG(RK3562_GRF_VI_CON1, 2, 6),
	[GRF_DPHY1_CSI2PHY_CLKLANE_EN] = GRF_REG(RK3562_GRF_VI_CON1, 1, 8),
	[GRF_DPHY1_CLK_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON1, 1, 9),
	[GRF_DPHY1_CSI2PHY_CLKLANE1_EN] = GRF_REG(RK3562_GRF_VI_CON1, 1, 10),
	[GRF_DPHY1_CLK1_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON1, 1, 11),
};

static const struct csi2dphy_reg rk3562_csi2dphy_regs[] = {
	[CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE),
	[CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN),
	[CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE),
	[CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN),
	[CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE),
	[CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN),
	[CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE),
	[CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN),
	[CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE),
	[CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN),
	[CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE),
	[CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN),
	[CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE),
	[CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN),
	[CSI2PHY_CLK1_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_LANE_EN),
};

static const struct grf_reg rk3576_grf_dphy_regs[] = {
	[GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_DPHY_CON0, 4, 0),
	[GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_DPHY_CON0, 4, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(GRF_DPHY_CON0, 2, 4),
	[GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(GRF_DPHY_CON0, 2, 6),
	[GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_DPHY_CON0, 1, 8),
	[GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 9),
	[GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_DPHY_CON0, 1, 10),
	[GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 11),
	[GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_SOC_CON5_RK3576, 1, 1),
	[GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(GRF_SOC_CON5_RK3576, 1, 2),
};

//define dcphy params
static struct rkmodule_csi_dphy_param rk3588_dcphy_param = {
	.vendor = PHY_VENDOR_SAMSUNG,
	.lp_vol_ref = 3,
	.lp_hys_sw = {3, 0, 0, 0},
	.lp_escclk_pol_sel = {1, 0, 0, 0},
	.skew_data_cal_clk = {0, 3, 3, 3},
	.clk_hs_term_sel = 2,
	.data_hs_term_sel = {2, 2, 2, 2},
	.reserved = {0},
};

/* These tables must be sorted by .range_h ascending. */
static const struct hsfreq_range rk3568_csi2_dphy_hw_hsfreq_ranges[] = {
	{ 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06},
	{ 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e},
	{ 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e},
	{1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37},
	{2199, 0x3c}, {2399, 0x41}, {2499, 0x46}
};

/* These tables must be sorted by .range_h ascending. */
static const struct hsfreq_range rk3588_csi2_dcphy_d_hw_hsfreq_ranges[] = {
	{ 80,  0x105}, { 100, 0x106}, { 120, 0x107}, { 140, 0x108},
	{ 160, 0x109}, { 180, 0x10a}, { 200, 0x10b}, { 220, 0x10c},
	{ 240, 0x10d}, { 270, 0x10e}, { 290, 0x10f}, { 310, 0x110},
	{ 330, 0x111}, { 350, 0x112}, { 370, 0x113}, { 390, 0x114},
	{ 410, 0x115}, { 430, 0x116}, { 450, 0x117}, { 470, 0x118},
	{ 490, 0x119}, { 510, 0x11a}, { 540, 0x11b}, { 560, 0x11c},
	{ 580, 0x11d}, { 600, 0x11e}, { 620, 0x11f}, { 640, 0x120},
	{ 660, 0x121}, { 680, 0x122}, { 700, 0x123}, { 720, 0x124},
	{ 740, 0x125}, { 760, 0x126}, { 790, 0x127}, { 810, 0x128},
	{ 830, 0x129}, { 850, 0x12a}, { 870, 0x12b}, { 890, 0x12c},
	{ 910, 0x12d}, { 930, 0x12e}, { 950, 0x12f}, { 970, 0x130},
	{ 990, 0x131}, {1010, 0x132}, {1030, 0x133}, {1060, 0x134},
	{1080, 0x135}, {1100, 0x136}, {1120, 0x137}, {1140, 0x138},
	{1160, 0x139}, {1180, 0x13a}, {1200, 0x13b}, {1220, 0x13c},
	{1240, 0x13d}, {1260, 0x13e}, {1280, 0x13f}, {1310, 0x140},
	{1330, 0x141}, {1350, 0x142}, {1370, 0x143}, {1390, 0x144},
	{1410, 0x145}, {1430, 0x146}, {1450, 0x147}, {1470, 0x148},
	{1490, 0x149}, {1580, 0x007}, {1740, 0x008}, {1910, 0x009},
	{2070, 0x00a}, {2240, 0x00b}, {2410, 0x00c}, {2570, 0x00d},
	{2740, 0x00e}, {2910, 0x00f}, {3070, 0x010}, {3240, 0x011},
	{3410, 0x012}, {3570, 0x013}, {3740, 0x014}, {3890, 0x015},
	{4070, 0x016}, {4240, 0x017}, {4400, 0x018}, {4500, 0x019},
};

static struct csi2_dphy_hw rk3568_csi2_dphy_hw = {
	.dphy_clks = rk3568_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3568_csi2_dphy_hw_clks),
	.csi2_clks = rk3568_csi2_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3568_csi2_clks),
	.csi2_rsts = rk3568_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3568_csi2_rsts),
	.hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3568_csi2dphy_regs,
	.grf_regs = rk3568_grf_dphy_regs,
	.chip_id = CHIP_ID_RK3568,
};

static struct csi2_dphy_hw rk3588_csi2_dphy_hw = {
	.dphy_clks = rk3588_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3588_csi2_dphy_hw_clks),
	.dphy_rsts = rk3588_csi2_dphy_hw_rsts,
	.num_dphy_rsts = ARRAY_SIZE(rk3588_csi2_dphy_hw_rsts),
	.csi2_clks = rk3588_csi2_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3588_csi2_clks),
	.csi2_rsts = rk3588_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3588_csi2_rsts),
	.hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3588_csi2dphy_regs,
	.grf_regs = rk3588_grf_dphy_regs,
	.chip_id = CHIP_ID_RK3588,
};

static struct csi2_dphy_hw rk3588_csi2_dcphy_hw = {
	.dphy_clks = rk3588_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3588_csi2_dphy_hw_clks),
	.csi2_clks = rk3588_csi2_dcphy_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3588_csi2_dcphy_clks),
	.csi2_rsts = rk3588_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3588_csi2_rsts),
	.hsfreq_ranges = rk3588_csi2_dcphy_d_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3588_csi2_dcphy_d_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3588_csi2dcphy_regs,
	.grf_regs = rk3588_grf_dcphy_regs,
	.chip_id = CHIP_ID_RK3588_DCPHY,
};

static struct csi2_dphy_hw rk3562_csi2_dphy_hw = {
	.dphy_clks = rk3562_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3562_csi2_dphy_hw_clks),
	.dphy_rsts = rk3562_csi2_dphy_hw_rsts,
	.num_dphy_rsts = ARRAY_SIZE(rk3562_csi2_dphy_hw_rsts),
	.csi2_clks = rk3562_csi2_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3562_csi2_clks),
	.csi2_rsts = rk3562_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3562_csi2_rsts),
	.hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3562_csi2dphy_regs,
	.grf_regs = rk3562_grf_dphy_regs,
	.chip_id = CHIP_ID_RK3562,
};

static struct csi2_dphy_hw rk3576_csi2_dphy_hw = {
	.dphy_clks = rk3576_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3576_csi2_dphy_hw_clks),
	.dphy_rsts = rk3576_csi2_dphy_hw_rsts,
	.num_dphy_rsts = ARRAY_SIZE(rk3576_csi2_dphy_hw_rsts),
	.csi2_clks = rk3576_csi2_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3576_csi2_clks),
	.csi2_rsts = rk3576_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3576_csi2_rsts),
	.hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3588_csi2dphy_regs,
	.grf_regs = rk3576_grf_dphy_regs,
	.chip_id = CHIP_ID_RK3576,
};

static struct csi2_dphy_hw rk3576_csi2_dcphy_hw = {
	.dphy_clks = rk3576_csi2_dphy_hw_clks,
	.num_dphy_clks = ARRAY_SIZE(rk3576_csi2_dphy_hw_clks),
	.csi2_clks = rk3576_csi2_dcphy_clks,
	.num_csi2_clks = ARRAY_SIZE(rk3576_csi2_dcphy_clks),
	.csi2_rsts = rk3576_csi2_rsts,
	.num_csi2_rsts = ARRAY_SIZE(rk3576_csi2_rsts),
	.hsfreq_ranges = rk3588_csi2_dcphy_d_hw_hsfreq_ranges,
	.num_hsfreq_ranges = ARRAY_SIZE(rk3588_csi2_dcphy_d_hw_hsfreq_ranges),
	.csi2dphy_regs = rk3588_csi2dcphy_regs,
	.grf_regs = rk3588_grf_dcphy_regs,
	.chip_id = CHIP_ID_RK3588_DCPHY,
};

static const struct cif_input_fmt in_fmts[] = {
	{
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_YUYV,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_YUYV,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_YUYV,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_YUYV,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_INTERLACED,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_YVYU8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_YVYU,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_YVYU,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_YVYU8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_YVYU,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_YVYU,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_INTERLACED,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_UYVY,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_UYVY,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_UYVY,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_UYVY,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_INTERLACED,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_VYUY8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_VYUY,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_VYUY,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_VYUY8_2X8,
		.dvp_fmt_val	= YUV_INPUT_422 | YUV_INPUT_ORDER_VYUY,
		.csi_fmt_val	= CSI_WRDDR_TYPE_YUV422,
		.csi_yuv_order	= CSI_YUV_INPUT_ORDER_VYUY,
		.fmt_type	= CIF_FMT_TYPE_YUV,
		.field		= V4L2_FIELD_INTERLACED,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_10,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW10,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_10,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW10,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_10,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW10,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_10,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW10,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_12,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW12,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_12,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW12,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_12,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW12,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_12,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW12,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_RGB888_1X24,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RGB888,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_8,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW8,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_10,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW10,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}, {
		.mbus_code	= MEDIA_BUS_FMT_Y12_1X12,
		.dvp_fmt_val	= INPUT_MODE_RAW | RAW_DATA_WIDTH_12,
		.csi_fmt_val	= CSI_WRDDR_TYPE_RAW12,
		.fmt_type	= CIF_FMT_TYPE_RAW,
		.field		= V4L2_FIELD_NONE,
	}
};

static const struct cif_output_fmt out_fmts[] = {
	{
		.fourcc = V4L2_PIX_FMT_NV16,
		.cplanes = 2,
		.mplanes = 1,
		.fmt_val = YUV_OUTPUT_422 | UV_STORAGE_ORDER_UVUV,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_YUV422,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_NV61,
		.fmt_val = YUV_OUTPUT_422 | UV_STORAGE_ORDER_VUVU,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_YUV422,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_NV12,
		.fmt_val = YUV_OUTPUT_420 | UV_STORAGE_ORDER_UVUV,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_YUV420SP,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_NV21,
		.fmt_val = YUV_OUTPUT_420 | UV_STORAGE_ORDER_VUVU,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_YUV420SP,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_YUYV,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_YVYU,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_UYVY,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_VYUY,
		.cplanes = 2,
		.mplanes = 1,
		.bpp = { 8, 16 },
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_YUV,
	}, {
		.fourcc = V4L2_PIX_FMT_RGB24,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 24 },
		.csi_fmt_val = CSI_WRDDR_TYPE_RGB888,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_RGB565,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_BGR666,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 18 },
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SRGGB8,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 8 },
		.raw_bpp = 8,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGRBG8,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 8 },
		.raw_bpp = 8,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGBRG8,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 8 },
		.raw_bpp = 8,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SBGGR8,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 8 },
		.raw_bpp = 8,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW8,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SRGGB10,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 10,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGRBG10,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 10,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGBRG10,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 10,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SBGGR10,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 10,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SRGGB12,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 12,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGRBG12,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 12,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SGBRG12,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 12,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SBGGR12,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 12,
		.csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_SBGGR16,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.raw_bpp = 16,
		.fmt_type = CIF_FMT_TYPE_RAW,
	}, {
		.fourcc = V4L2_PIX_FMT_Y16,
		.cplanes = 1,
		.mplanes = 1,
		.bpp = { 16 },
		.fmt_type = CIF_FMT_TYPE_RAW,
	}

	/* TODO: We can support NV12M/NV21M/NV16M/NV61M too */
};

static void rkcif_write_reg(struct vehicle_cif *cif,
			  enum cif_reg_index index, u32 val)
{
	void __iomem *base = cif->base;
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];
	int csi_offset = 0;

	if (cif->inf_id == RKCIF_MIPI_LVDS &&
	    index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
	    index <= CIF_REG_MIPI_ON_PAD) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			csi_offset = cif->csi_host_idx * 0x100;
		} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
			if (cif->csi_host_idx < 3)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x500;
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->csi_host_idx < 2)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x100 + cif->csi_host_idx * 0x100;
		}
	}

	if (index < CIF_REG_INDEX_MAX) {
		if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) {
			write_reg(base, reg->offset + csi_offset, val);
		} else {
			VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				 index, reg->name, val);
		}
	}
	VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n",
				__func__, reg->name, reg->offset, csi_offset, val);
}

static void rkcif_write_reg_or(struct vehicle_cif *cif,
			  enum cif_reg_index index, u32 val)
{
	void __iomem *base = cif->base;
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];
	unsigned int reg_val = 0x0;
	int csi_offset = 0;

	if (cif->inf_id == RKCIF_MIPI_LVDS &&
	    index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
	    index <= CIF_REG_MIPI_ON_PAD) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			csi_offset = cif->csi_host_idx * 0x100;
		} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
			if (cif->csi_host_idx < 3)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x500;
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->csi_host_idx < 2)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x100 + cif->csi_host_idx * 0x100;
		}
	}

	if (index < CIF_REG_INDEX_MAX) {
		if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) {
			reg_val = read_reg(base, reg->offset + csi_offset);
			reg_val |= val;
			write_reg(base, reg->offset + csi_offset, reg_val);
		} else {
			VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				 index, reg->name, val);
		}
	}
	VEHICLE_DG("@%s register[%s] offset(0x%x)  csi_offset(0x%x) value:0x%x !\n",
				__func__, reg->name, reg->offset, csi_offset, reg_val);
}

static void rkcif_write_reg_and(struct vehicle_cif *cif,
			  enum cif_reg_index index, u32 val)
{
	void __iomem *base = cif->base;
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];
	unsigned int reg_val = 0x0;
	int csi_offset = 0;

	if (cif->inf_id == RKCIF_MIPI_LVDS &&
	    index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
	    index <= CIF_REG_MIPI_ON_PAD) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			csi_offset = cif->csi_host_idx * 0x100;
		} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
			if (cif->csi_host_idx < 3)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x500;
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->csi_host_idx < 2)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x100 + cif->csi_host_idx * 0x100;
		}
	}

	if (index < CIF_REG_INDEX_MAX) {
		if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) {
			reg_val = read_reg(base, reg->offset + csi_offset);
			reg_val &= val;
			write_reg(base, reg->offset + csi_offset, reg_val);
		} else {
			VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				 index, reg->name, val);
		}
	}
	VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n",
				__func__, reg->name, reg->offset, csi_offset, reg_val);
}

static unsigned int rkcif_read_reg(struct vehicle_cif *cif,
				 enum cif_reg_index index)
{
	unsigned int val = 0x0;
	void __iomem *base = cif->base;
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];
	int csi_offset = 0;

	if (cif->inf_id == RKCIF_MIPI_LVDS &&
	    index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
	    index <= CIF_REG_MIPI_ON_PAD) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			csi_offset = cif->csi_host_idx * 0x100;
		} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
			if (cif->csi_host_idx < 3)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x500;
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->csi_host_idx < 2)
				csi_offset = cif->csi_host_idx * 0x200;
			else
				csi_offset = 0x100 + cif->csi_host_idx * 0x100;
		}
	}

	if (index < CIF_REG_INDEX_MAX) {
		if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0)
			val = read_reg(base, reg->offset + csi_offset);
		else
			VEHICLE_INFO("read index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				 index, reg->name, val);
	}
	VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n",
				__func__, reg->name, reg->offset, csi_offset, val);
	return val;
}

static void rkvehicle_cif_write_grf_reg(struct vehicle_cif *cif,
			 enum cif_reg_index index, u32 val)
{
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];

	if (index < CIF_REG_INDEX_MAX) {
		if (index > CIF_REG_DVP_CTRL) {
			if (!IS_ERR(cif->regmap_grf))
				regmap_write(cif->regmap_grf, reg->offset, val);
		} else {
			VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				 index, reg->name, val);
		}
		VEHICLE_DG("@%s reg[%s] offset(0x%x): 0x%x !\n",
				__func__, reg->name, reg->offset, val);
	}
}

static u32 rkvehicle_cif_read_grf_reg(struct vehicle_cif *cif,
			   enum cif_reg_index index)
{
	const struct vehicle_cif_reg *reg = &cif->cif_regs[index];
	u32 val = 0xffff;

	if (index < CIF_REG_INDEX_MAX) {
		if (index > CIF_REG_DVP_CTRL) {
			if (!IS_ERR(cif->regmap_grf))
				regmap_read(cif->regmap_grf, reg->offset, &val);
		} else {
			VEHICLE_INFO("read index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n",
				index, reg->name, val);
		}
		VEHICLE_DG("@%s reg[%s] offset(0x%x): 0x%x !\n",
				__func__, reg->name, reg->offset, val);
	}

	return val;
}

static inline void write_csi2_dphy_reg(struct csi2_dphy_hw *hw,
					    int index, u32 value)
{
	const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index];

	if ((index == CSI2PHY_REG_CTRL_LANE_ENABLE) ||
	    (index == CSI2PHY_CLK_LANE_ENABLE) ||
	    ((index != CSI2PHY_REG_CTRL_LANE_ENABLE) &&
	     (reg->offset != 0x0)))
		writel(value, hw->csi2_dphy_base + reg->offset);

	VEHICLE_DG("@%s offset(0x%x) reg val: 0x%x !\n",
				__func__, reg->offset, value);
}

static inline void write_csi2_dphy_reg_mask(struct csi2_dphy_hw *hw,
					    int index, u32 value, u32 mask)
{
	const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index];
	u32 read_val = 0;

	read_val = readl(hw->csi2_dphy_base + reg->offset);
	read_val &= ~mask;
	read_val |= value;
	writel(read_val, hw->csi2_dphy_base + reg->offset);
}

static inline void read_csi2_dphy_reg(struct csi2_dphy_hw *hw,
					   int index, u32 *value)
{
	const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index];

	if ((index == CSI2PHY_REG_CTRL_LANE_ENABLE) ||
	    (index == CSI2PHY_CLK_LANE_ENABLE) ||
	    ((index != CSI2PHY_REG_CTRL_LANE_ENABLE) &&
	     (reg->offset != 0x0)))
		*value = readl(hw->csi2_dphy_base + reg->offset);

	VEHICLE_DG("@%s offset(0x%x) reg val: 0x%x !\n",
				__func__, reg->offset, *value);
}

static void csi_mipidphy_wr_ths_settle(struct csi2_dphy_hw *hw,
					      int hsfreq,
					      enum csi2_dphy_lane lane)
{
	unsigned int val = 0;
	unsigned int offset;

	switch (lane) {
	case CSI2_DPHY_LANE_CLOCK:
		offset = CSI2PHY_CLK_THS_SETTLE;
		break;
	case CSI2_DPHY_LANE_CLOCK1:
		offset = CSI2PHY_CLK1_THS_SETTLE;
		break;
	case CSI2_DPHY_LANE_DATA0:
		offset = CSI2PHY_LANE0_THS_SETTLE;
		break;
	case CSI2_DPHY_LANE_DATA1:
		offset = CSI2PHY_LANE1_THS_SETTLE;
		break;
	case CSI2_DPHY_LANE_DATA2:
		offset = CSI2PHY_LANE2_THS_SETTLE;
		break;
	case CSI2_DPHY_LANE_DATA3:
		offset = CSI2PHY_LANE3_THS_SETTLE;
		break;
	default:
		return;
	}

	read_csi2_dphy_reg(hw, offset, &val);
	val = (val & ~0x7f) | hsfreq;
	write_csi2_dphy_reg(hw, offset, val);
}

static void rkvehicle_cif_cfg_dvp_clk_sampling_edge(struct vehicle_cif *cif,
					enum rkcif_clk_edge edge)
{
	u32 val = 0x0;

	if (!IS_ERR(cif->regmap_grf)) {
		if (cif->chip_id == CHIP_RK3568_VEHICLE_CIF) {
			if (edge == RKCIF_CLK_RISING)
				val = RK3568_CIF_PCLK_SAMPLING_EDGE_RISING;
			else
				val = RK3568_CIF_PCLK_SAMPLING_EDGE_FALLING;
		}
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			if (edge == RKCIF_CLK_RISING)
				val = RK3588_CIF_PCLK_SAMPLING_EDGE_RISING;
			else
				val = RK3588_CIF_PCLK_SAMPLING_EDGE_FALLING;
		}
		rkvehicle_cif_write_grf_reg(cif, CIF_REG_GRF_CIFIO_CON, val);
	}
}

static int rkcif_dvp_get_input_yuv_order(struct vehicle_cfg *cfg)
{
	unsigned int mask;

	switch (cfg->mbus_code) {
	case MEDIA_BUS_FMT_UYVY8_2X8:
		mask = CSI_YUV_INPUT_ORDER_UYVY >> 11;
		break;
	case MEDIA_BUS_FMT_VYUY8_2X8:
		mask = CSI_YUV_INPUT_ORDER_VYUY >> 11;
		break;
	case MEDIA_BUS_FMT_YUYV8_2X8:
		mask = CSI_YUV_INPUT_ORDER_YUYV >> 11;
		break;
	case MEDIA_BUS_FMT_YVYU8_2X8:
		mask = CSI_YUV_INPUT_ORDER_YVYU >> 11;
		break;
	default:
		mask = CSI_YUV_INPUT_ORDER_UYVY >> 11;
		break;
	}
	return mask;
}

static int cif_stream_setup(struct vehicle_cif *cif)
{
	struct vehicle_cfg *cfg = &cif->cif_cfg;
	u32 val, mbus_flags,
	    xfer_mode = 0, yc_swap = 0,
	    inputmode = 0, mipimode = 0,
	    input_format = 0, output_format = 0, crop = 0,
	    out_fmt_mask = 0,
	    multi_id_en = BT656_1120_MULTI_ID_DISABLE,
	    multi_id_mode = BT656_1120_MULTI_ID_MODE_1,
	    multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB,
	    bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES;
	u32 sav_detect = BT656_DETECT_SAV;
	u32 in_fmt_yuv_order = 0;

	mbus_flags = cfg->mbus_flags;
	/* set dvp clk sample edge */
	if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
		rkvehicle_cif_cfg_dvp_clk_sampling_edge(cif, RKCIF_CLK_RISING);
	else
		rkvehicle_cif_cfg_dvp_clk_sampling_edge(cif, RKCIF_CLK_FALLING);

	inputmode = cfg->input_format<<2; //INPUT_MODE_YUV or INPUT_MODE_BT656_YUV422
	//YUV_INPUT_ORDER_UYVY, MEDIA_BUS_FMT_UYVY8_2X8, CCIR_INPUT_ORDER_ODD
	input_format = (cfg->yuv_order<<5) | YUV_INPUT_422 | (cfg->field_order<<9);
	if (cfg->output_format == CIF_OUTPUT_FORMAT_420)
		output_format = YUV_OUTPUT_420 | UV_STORAGE_ORDER_UVUV;
	else
		output_format = YUV_OUTPUT_422 | UV_STORAGE_ORDER_UVUV;

	if (cif->chip_id == CHIP_RK3568_VEHICLE_CIF) {
		val = cfg->vsync | (cfg->href<<1) | inputmode | mipimode
		   | input_format | output_format
		   | xfer_mode | yc_swap | multi_id_en
		   | multi_id_sel | multi_id_mode | bt1120_edge_mode;
	} else {
		out_fmt_mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) |
				(CSI_YUV_OUTPUT_ORDER_UYVY << 1);
		in_fmt_yuv_order = rkcif_dvp_get_input_yuv_order(cfg);
		val = cfg->vsync | (cfg->href<<1) | inputmode
		   | in_fmt_yuv_order | out_fmt_mask
		   | yc_swap | multi_id_en | multi_id_sel
		   | sav_detect | multi_id_mode | bt1120_edge_mode;
	}

	if (cif->chip_id >= CHIP_RK3576_VEHICLE_CIF)
		val |= DVP_UVDS_EN;

	rkcif_write_reg(cif, CIF_REG_DVP_FOR, val);

	rkcif_write_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH, cfg->width);
	rkcif_write_reg(cif, CIF_REG_DVP_SET_SIZE,
		      cfg->width | (cfg->height << 16));

	crop = (cfg->start_x | (cfg->start_y<<16));
	rkcif_write_reg(cif, CIF_REG_DVP_CROP, crop);

	rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS);

	if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) {
		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, INTSTAT_CLS);
		rkcif_write_reg(cif, CIF_REG_DVP_SCL_CTRL, ENABLE_YUV_16BIT_BYPASS);
		rkcif_write_reg(cif, CIF_REG_DVP_INTEN,
			FRAME_END_EN | INTSTAT_ERR |
			PST_INF_FRAME_END);
		/* enable line int for sof */
		rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1);
		rkcif_write_reg(cif, CIF_REG_DVP_INTEN, LINE_INT_EN);
	} else if (cif->chip_id < CHIP_RK3576_VEHICLE_CIF) {
		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3c3ffff);
		rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x033ffff);//0x3c3ffff
	} else {
		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3c3ffff);
		rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x3c3ff0f);
	}

	cif->interlaced_enable = false;

	return 0;
}

static inline void csi2_dphy_write_sys_grf_reg(struct csi2_dphy_hw *hw,
				     int index, u8 value)
{
	const struct grf_reg *reg = &hw->grf_regs[index];
	unsigned int val = HIWORD_UPDATE(value, reg->mask, reg->shift);

	if (reg->shift)
		regmap_write(hw->regmap_sys_grf, reg->offset, val);
}

static inline void csi2_dphy_write_grf_reg(struct csi2_dphy_hw *hw,
				     int index, u8 value)
{
	const struct grf_reg *reg = &hw->grf_regs[index];
	unsigned int val = HIWORD_UPDATE(value, reg->mask, reg->shift);

	if (reg->shift)
		regmap_write(hw->regmap_grf, reg->offset, val);
}

static inline u32 csi2_dphy_read_grf_reg(struct csi2_dphy_hw *hw, int index)
{
	const struct grf_reg *reg = &hw->grf_regs[index];
	unsigned int val = 0;

	if (reg->shift) {
		regmap_read(hw->regmap_grf, reg->offset, &val);
		val = (val >> reg->shift) & reg->mask;
	}

	return val;
}

static void csi2_dphy_config_dual_mode(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	u32 val;

	val = ~GRF_CSI2PHY_LANE_SEL_SPLIT;
	if (cif->dphy_hw->phy_index < 3) {
		csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN,
				GENMASK(cif->cif_cfg.lanes - 1, 0));
		csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN, 0x1);
		if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF &&
				cif->chip_id != CHIP_RK3576_VEHICLE_CIF)
			csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL, val);
		else
			csi2_dphy_write_sys_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL, val);
	} else {
		if (cif->chip_id <= CHIP_RK3588_VEHICLE_CIF ||
				cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN,
					GENMASK(cif->cif_cfg.lanes - 1, 0));
			csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN, 0x1);
		} else {
			csi2_dphy_write_grf_reg(hw, GRF_DPHY1_CSI2PHY_DATALANE_EN,
					GENMASK(cif->cif_cfg.lanes - 1, 0));
			csi2_dphy_write_grf_reg(hw, GRF_DPHY1_CSI2PHY_CLKLANE_EN, 0x1);
		}
		if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF &&
				cif->chip_id != CHIP_RK3576_VEHICLE_CIF)
			csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY1_LANE_SEL, val);
		else
			csi2_dphy_write_sys_grf_reg(hw, GRF_DPHY_CSI2PHY1_LANE_SEL, val);
	}
}

static int vehicle_csi2_dphy_stream_start(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	const struct hsfreq_range *hsfreq_ranges = hw->hsfreq_ranges;
	int num_hsfreq_ranges = hw->num_hsfreq_ranges;
	int i, hsfreq = 0;
	u32 val = 0, pre_val;


	mutex_lock(&hw->mutex);

	/* set data lane num and enable clock lane */
	/*
	 * for rk356x: dphy0 is used just for full mode,
	 *             dphy1 is used just for split mode,uses lane0_1,
	 *             dphy2 is used just for split mode,uses lane2_3
	 */
	read_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, &pre_val);
	val |= (GENMASK(cif->cif_cfg.lanes - 1, 0) <<
		CSI2_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT) |
		(0x1 << CSI2_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT);

	val |= pre_val;
	write_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, val);

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		write_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, 0x1e);
		write_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, 0x1f);
		csi2_dphy_config_dual_mode(cif);
	}

	/* not into receive mode/wait stopstate */
	csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_FORCERXMODE, 0x0);

	/* enable calibration */
	if (hw->data_rate_mbps > 1500) {
		write_csi2_dphy_reg(hw, CSI2PHY_CLK_CALIB_ENABLE, 0x80);
		if (cif->cif_cfg.lanes > 0x00)
			write_csi2_dphy_reg(hw, CSI2PHY_LANE0_CALIB_ENABLE, 0x80);
		if (cif->cif_cfg.lanes > 0x01)
			write_csi2_dphy_reg(hw, CSI2PHY_LANE1_CALIB_ENABLE, 0x80);
		if (cif->cif_cfg.lanes > 0x02)
			write_csi2_dphy_reg(hw, CSI2PHY_LANE2_CALIB_ENABLE, 0x80);
		if (cif->cif_cfg.lanes > 0x03)
			write_csi2_dphy_reg(hw, CSI2PHY_LANE3_CALIB_ENABLE, 0x80);
	}

	/* set clock lane and data lane */
	for (i = 0; i < num_hsfreq_ranges; i++) {
		if (hsfreq_ranges[i].range_h >= hw->data_rate_mbps) {
			hsfreq = hsfreq_ranges[i].cfg_bit;
			break;
		}
	}

	if (i == num_hsfreq_ranges) {
		i = num_hsfreq_ranges - 1;
		dev_warn(hw->dev, "data rate: %lld mbps, max support %d mbps",
			 hw->data_rate_mbps, hsfreq_ranges[i].range_h + 1);
		hsfreq = hsfreq_ranges[i].cfg_bit;
	}

	VEHICLE_DG("mipi data_rate_mbps %lld, matched bit(0x%0x), lanes(%d)\n",
			hw->data_rate_mbps, hsfreq, cif->cif_cfg.lanes);

	csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_CLOCK);
	if (cif->cif_cfg.lanes > 0x00)
		csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA0);
	if (cif->cif_cfg.lanes > 0x01)
		csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA1);
	if (cif->cif_cfg.lanes > 0x02)
		csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA2);
	if (cif->cif_cfg.lanes > 0x03)
		csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA3);

	atomic_inc(&hw->stream_cnt);

	mutex_unlock(&hw->mutex);

	return 0;
}

static void vehicle_samsung_dcphy_rx_config_settle(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;
	const struct hsfreq_range *hsfreq_ranges = NULL;
	int num_hsfreq_ranges = 0;
	int i, hsfreq = 0;
	u32 sot_sync = 0;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		hsfreq_ranges = hw->hsfreq_ranges;
		num_hsfreq_ranges = hw->num_hsfreq_ranges;
		sot_sync = 0x03;
	}

	/* set data lane */
	for (i = 0; i < num_hsfreq_ranges; i++) {
		if (hsfreq_ranges[i].range_h >= hw->data_rate_mbps) {
			hsfreq = hsfreq_ranges[i].cfg_bit;
			break;
		}
	}

	/*clk settle fix to 0x301*/
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY)
		regmap_write(samsung->regmap, RX_CLK_THS_SETTLE, 0x301);

	if (cif->cif_cfg.lanes > 0x00) {
		regmap_update_bits(samsung->regmap, RX_LANE0_THS_SETTLE, 0x1ff, hsfreq);
		regmap_update_bits(samsung->regmap, RX_LANE0_ERR_SOT_SYNC, 0xff, sot_sync);
	}
	if (cif->cif_cfg.lanes > 0x01) {
		regmap_update_bits(samsung->regmap, RX_LANE1_THS_SETTLE, 0x1ff, hsfreq);
		regmap_update_bits(samsung->regmap, RX_LANE1_ERR_SOT_SYNC, 0xff, sot_sync);
	}
	if (cif->cif_cfg.lanes > 0x02) {
		regmap_update_bits(samsung->regmap, RX_LANE2_THS_SETTLE, 0x1ff, hsfreq);
		regmap_update_bits(samsung->regmap, RX_LANE2_ERR_SOT_SYNC, 0xff, sot_sync);
	}
	if (cif->cif_cfg.lanes > 0x03) {
		regmap_update_bits(samsung->regmap, RX_LANE3_THS_SETTLE, 0x1ff, hsfreq);
		regmap_update_bits(samsung->regmap, RX_LANE3_ERR_SOT_SYNC, 0xff, sot_sync);
	}
}

static int vehicle_samsung_dcphy_rx_config_common(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;
	u32 dlysel = 0;
	int i = 0;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		if (hw->data_rate_mbps < 1500)
			dlysel = 0;
		else if (hw->data_rate_mbps < 2000)
			dlysel = 3 << 8;
		else if (hw->data_rate_mbps < 3000)
			dlysel = 2 << 8;
		else if (hw->data_rate_mbps < 4000)
			dlysel = 1 << 8;
		else if (hw->data_rate_mbps < 6500)
			dlysel = 0;
		if (hw->dphy_param->clk_hs_term_sel > 0x7) {
			dev_err(hw->dev, "clk_hs_term_sel error param %d\n",
				hw->dphy_param->clk_hs_term_sel);
			return -EINVAL;
		}
		for (i = 0; i < cif->cif_cfg.lanes; i++) {
			if (hw->dphy_param->data_hs_term_sel[i] > 0x7) {
				dev_err(hw->dev, "data_hs_term_sel[%d] error param %d\n",
					i,
					hw->dphy_param->data_hs_term_sel[i]);
				return -EINVAL;
			}
			if (hw->dphy_param->lp_hys_sw[i] > 0x3) {
				dev_err(hw->dev, "lp_hys_sw[%d] error param %d\n",
					i,
					hw->dphy_param->lp_hys_sw[i]);
				return -EINVAL;
			}
			if (hw->dphy_param->lp_escclk_pol_sel[i] > 0x1) {
				dev_err(hw->dev, "lp_escclk_pol_sel[%d] error param %d\n",
					i,
					hw->dphy_param->lp_escclk_pol_sel[i]);
				return -EINVAL;
			}
			if (hw->dphy_param->skew_data_cal_clk[i] > 0x1f) {
				dev_err(hw->dev, "skew_data_cal_clk[%d] error param %d\n",
					i,
					hw->dphy_param->skew_data_cal_clk[i]);
				return -EINVAL;
			}
		}
		regmap_write(samsung->regmap, RX_S0C_GNR_CON1, 0x1450);
		regmap_write(samsung->regmap, RX_S0C_ANA_CON1, 0x8000);
		regmap_write(samsung->regmap, RX_S0C_ANA_CON2, hw->dphy_param->clk_hs_term_sel);
		regmap_write(samsung->regmap, RX_S0C_ANA_CON3, 0x0600);
		if (cif->cif_cfg.lanes > 0x00) {
			regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450);
			regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000);
			regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, dlysel |
				     hw->dphy_param->data_hs_term_sel[0]);
			regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x0600 |
				     (hw->dphy_param->lp_hys_sw[0] << 4) |
				     (hw->dphy_param->lp_escclk_pol_sel[0] << 11));
			regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40);
			regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON2,
				     hw->dphy_param->skew_data_cal_clk[0]);
			if (hw->data_rate_mbps >= 1500 &&
				cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) {
				regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON0, BIT(0));
				regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON4, 0x81A);
			}
		}
		if (cif->cif_cfg.lanes > 0x01) {
			regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450);
			regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000);
			regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, dlysel |
				     hw->dphy_param->data_hs_term_sel[1]);
			regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x0600 |
				     (hw->dphy_param->lp_hys_sw[1] << 4) |
				     (hw->dphy_param->lp_escclk_pol_sel[1] << 11));
			regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40);
			regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON2,
				     hw->dphy_param->skew_data_cal_clk[1]);
			if (hw->data_rate_mbps >= 1500 &&
				cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) {
				regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON0, BIT(0));
				regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON4, 0x81A);
			}
		}
		if (cif->cif_cfg.lanes > 0x02) {
			regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450);
			regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000);
			regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, dlysel |
				     hw->dphy_param->data_hs_term_sel[2]);
			regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x0600 |
				     (hw->dphy_param->lp_hys_sw[2] << 4) |
				     (hw->dphy_param->lp_escclk_pol_sel[2] << 11));
			regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40);
			regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON2,
				     hw->dphy_param->skew_data_cal_clk[2]);
			if (hw->data_rate_mbps >= 1500 &&
				cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) {
				regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON0, BIT(0));
				regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON4, 0x81A);
			}
		}
		if (cif->cif_cfg.lanes > 0x03) {
			regmap_write(samsung->regmap, RX_S0D3_GNR_CON1, 0x1450);
			regmap_write(samsung->regmap, RX_S0D3_ANA_CON1, 0x8000);
			regmap_write(samsung->regmap, RX_S0D3_ANA_CON2, dlysel |
				     hw->dphy_param->data_hs_term_sel[3]);
			regmap_write(samsung->regmap, RX_S0D3_ANA_CON3, 0x0600 |
				     (hw->dphy_param->lp_hys_sw[3] << 4) |
				     (hw->dphy_param->lp_escclk_pol_sel[3] << 11));
			regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON2,
				     hw->dphy_param->skew_data_cal_clk[3]);
			if (hw->data_rate_mbps >= 1500 &&
				cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) {
				regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON0, BIT(0));
				regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON4, 0x81A);
			}
		}
	}

	return 0;
}

static int vehicle_samsung_dcphy_rx_lane_enable(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;
	u32 sts;
	int ret = 0;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY)
		regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, PHY_ENABLE);

	if (cif->cif_cfg.lanes > 0x00)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, PHY_ENABLE);
	if (cif->cif_cfg.lanes > 0x01)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, PHY_ENABLE);
	if (cif->cif_cfg.lanes > 0x02)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, PHY_ENABLE);
	if (cif->cif_cfg.lanes > 0x03)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, PHY_ENABLE);

	/*wait for clk lane ready*/
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		ret = regmap_read_poll_timeout(samsung->regmap, RX_CLK_LANE_ENABLE,
				       sts, (sts & PHY_READY), 200, 4000);
		if (ret < 0) {
			dev_err(samsung->dev, "phy rx clk lane is not locked\n");
			return -EINVAL;
		}
	}

	/*wait for data lane ready*/
	if (cif->cif_cfg.lanes > 0x00) {
		ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE0_ENABLE,
				       sts, (sts & PHY_READY), 200, 2000);
		if (ret < 0) {
			dev_err(samsung->dev, "phy rx data lane 0 is not locked\n");
			return -EINVAL;
		}
	}
	if (cif->cif_cfg.lanes > 0x01) {
		ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE1_ENABLE,
				       sts, (sts & PHY_READY), 200, 2000);
		if (ret < 0) {
			dev_err(samsung->dev, "phy rx data lane 1 is not locked\n");
			return -EINVAL;
		}
	}
	if (cif->cif_cfg.lanes > 0x02) {
		ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE2_ENABLE,
				       sts, (sts & PHY_READY), 200, 2000);
		if (ret < 0) {
			dev_err(samsung->dev, "phy rx data lane 2 is not locked\n");
			return -EINVAL;
		}
	}

	if (cif->cif_cfg.lanes > 0x03) {
		ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE3_ENABLE,
				       sts, (sts & PHY_READY), 200, 2000);
		if (ret < 0) {
			dev_err(samsung->dev, "phy rx data lane 3 is not locked\n");
			return -EINVAL;
		}
	}
	return 0;
}

static void vehicle_samsung_mipi_dcphy_bias_block_enable(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;
	struct csi2_dphy_hw *csi_dphy = samsung->dphy_vehicle[0];
	u32 bias_con2 = 0x3223;

	if (csi_dphy &&
	    csi_dphy->dphy_param->lp_vol_ref != 3 &&
	    csi_dphy->dphy_param->lp_vol_ref < 0x7) {
		bias_con2 &= 0xfffffff8;
		bias_con2 |= csi_dphy->dphy_param->lp_vol_ref;
		dev_info(samsung->dev,
			 "rx change lp_vol_ref to %d, it may cause tx exception\n",
			 csi_dphy->dphy_param->lp_vol_ref);
	}
	regmap_write(samsung->regmap, BIAS_CON0, 0x0010);
	regmap_write(samsung->regmap, BIAS_CON1, 0x0110);
	regmap_write(samsung->regmap, BIAS_CON2, bias_con2);

	/* default output voltage select:
	 * dphy: 400mv
	 * cphy: 530mv
	 */
	if (samsung->c_option)
		regmap_update_bits(samsung->regmap, BIAS_CON4,
				   I_MUX_SEL_MASK, I_MUX_SEL(2));
}

static int vehicle_csi2_dcphy_stream_start(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;
	int ret = 0;

	dev_info(hw->dev, "mipi dcphy stream on\n");
	mutex_lock(&hw->mutex);

	if (samsung->s_phy_rst)
		reset_control_assert(samsung->s_phy_rst);

	vehicle_samsung_mipi_dcphy_bias_block_enable(cif);
	ret = vehicle_samsung_dcphy_rx_config_common(cif);
	if (ret)
		goto out_streamon;

	vehicle_samsung_dcphy_rx_config_settle(cif);

	ret = vehicle_samsung_dcphy_rx_lane_enable(cif);
	if (ret)
		goto out_streamon;

	if (samsung->s_phy_rst)
		reset_control_deassert(samsung->s_phy_rst);
	atomic_inc(&hw->stream_cnt);
	mutex_unlock(&hw->mutex);

	return 0;

out_streamon:
	if (samsung->s_phy_rst)
		reset_control_deassert(samsung->s_phy_rst);
	mutex_unlock(&hw->mutex);
	dev_err(hw->dev, "stream on error\n");
	return -EINVAL;
}

static int vehicle_csi2_dcphy_stream_stop(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct samsung_mipi_dcphy *samsung = hw->samsung_phy;

	dev_info(hw->dev, "mipi dcphy stream off\n");
	if (atomic_dec_return(&hw->stream_cnt))
		return 0;

	mutex_lock(&hw->mutex);

	if (samsung->s_phy_rst)
		reset_control_assert(samsung->s_phy_rst);
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY)
		regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, 0);

	if (cif->cif_cfg.lanes > 0x00)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, 0);
	if (cif->cif_cfg.lanes > 0x01)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, 0);
	if (cif->cif_cfg.lanes > 0x02)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, 0);
	if (cif->cif_cfg.lanes > 0x03)
		regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, 0);

	if (samsung->s_phy_rst)
		reset_control_deassert(samsung->s_phy_rst);
	usleep_range(500, 1000);

	mutex_unlock(&hw->mutex);

	return 0;
}

static void vehicle_csi2_disable(struct vehicle_cif *cif)
{
	void __iomem *base = cif->csi2_base;

	vehicle_write_csihost_reg(base, CSIHOST_RESETN, 0);
	vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff);
	vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff);
}

static void vehicle_csi2_enable(struct vehicle_cif *cif,
				enum host_type_t host_type)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	void __iomem *base = hw->csi2_base;
	int lanes = cif->cif_cfg.lanes;

	vehicle_write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1);

	if (host_type == RK_DSI_RXHOST) {
		vehicle_write_csihost_reg(base, CSIHOST_CONTROL,
				  SW_CPHY_EN(0) | SW_DSI_EN(1) |
				  SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) |
				  SW_DATATYPE_LS(0x21) | SW_DATATYPE_LE(0x31));
		/* Disable some error interrupt when HOST work on DSI RX mode */
		vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0);
		vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xff00);
	} else {
		vehicle_write_csihost_reg(base, CSIHOST_CONTROL,
				  SW_CPHY_EN(0) | SW_DSI_EN(0) |
				  SW_DATATYPE_FS(0x0) | SW_DATATYPE_FE(0x01) |
				  SW_DATATYPE_LS(0x02) | SW_DATATYPE_LE(0x03));
		vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0);
		vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xf000);
	}

	vehicle_write_csihost_reg(base, CSIHOST_RESETN, 1);
}

static int vehicle_csi2_stream_start(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	enum host_type_t host_type;
	int i;

	host_type = RK_CSI_RXHOST;
	vehicle_csi2_enable(cif, host_type);
	for (i = 0; i < RK_CSI2_ERR_MAX; i++)
		hw->err_list[i].cnt = 0;

	return 0;
}

static void vehicle_cif_csi_get_vc_num(struct vehicle_cif *cif)
{
	int vc_num = 0;
	unsigned int mbus_flags = cif->cif_cfg.mbus_flags;

	for (vc_num = 0; vc_num < RKCIF_MAX_CSI_CHANNEL; vc_num++) {
		if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_0) {
			cif->channels[vc_num].vc = vc_num;
			mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_0;
			continue;
		}
		if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_1) {
			cif->channels[vc_num].vc = vc_num;
			mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_1;
			continue;
		}

		if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_2) {
			cif->channels[vc_num].vc = vc_num;
			mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_2;
			continue;
		}

		if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_3) {
			cif->channels[vc_num].vc = vc_num;
			mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_3;
			continue;
		}
	}

	cif->num_channels = vc_num ? (vc_num - 1) : 1;
	if (cif->num_channels == 1)
		cif->channels[0].vc = 0;
}

static const struct
cif_input_fmt *find_input_fmt(u32 mbus_code)
{
	const struct cif_input_fmt *fmt;
	u32 i;

	for (i = 0; i < ARRAY_SIZE(in_fmts); i++) {
		fmt = &in_fmts[i];
		if (mbus_code == fmt->mbus_code)
			return fmt;
	}

	return NULL;
}

static const struct
cif_output_fmt *find_output_fmt(u32 pixelfmt)
{
	const struct cif_output_fmt *fmt;
	u32 i;

	for (i = 0; i < ARRAY_SIZE(out_fmts); i++) {
		fmt = &out_fmts[i];
		if (fmt->fourcc == pixelfmt)
			return fmt;
	}

	return NULL;
}

static enum cif_reg_index get_reg_index_of_id_ctrl0(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_ID0_CTRL0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_ID1_CTRL0;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_ID2_CTRL0;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_ID3_CTRL0;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_ID0_CTRL0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_id_ctrl1(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_ID0_CTRL1;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_ID1_CTRL1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_ID2_CTRL1;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_ID3_CTRL1;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_ID0_CTRL1;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm0_y_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm_num(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_FRAME_NUM_VC0;
		break;
	case 1:
		index = CIF_REG_MIPI_FRAME_NUM_VC1;
		break;
	case 2:
		index = CIF_REG_MIPI_FRAME_NUM_VC2;
		break;
	case 3:
		index = CIF_REG_MIPI_FRAME_NUM_VC3;
		break;
	default:
		index = CIF_REG_MIPI_FRAME_NUM_VC0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm1_y_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm0_uv_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm1_uv_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm0_y_vlw(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm1_y_vlw(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm0_uv_vlw(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_frm1_uv_vlw(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0;
		break;
	}

	return index;
}

static enum cif_reg_index get_reg_index_of_id_crop_start(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_MIPI_LVDS_ID0_CROP_START;
		break;
	case 1:
		index = CIF_REG_MIPI_LVDS_ID1_CROP_START;
		break;
	case 2:
		index = CIF_REG_MIPI_LVDS_ID2_CROP_START;
		break;
	case 3:
		index = CIF_REG_MIPI_LVDS_ID3_CROP_START;
		break;
	default:
		index = CIF_REG_MIPI_LVDS_ID0_CROP_START;
		break;
	}

	return index;
}

static enum cif_reg_index get_dvp_reg_index_of_frm0_y_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_DVP_FRM0_ADDR_Y;
		break;
	case 1:
		index = CIF_REG_DVP_FRM0_ADDR_Y_ID1;
		break;
	case 2:
		index = CIF_REG_DVP_FRM0_ADDR_Y_ID2;
		break;
	case 3:
		index = CIF_REG_DVP_FRM0_ADDR_Y_ID3;
		break;
	default:
		index = CIF_REG_DVP_FRM0_ADDR_Y;
		break;
	}

	return index;
}

static enum cif_reg_index get_dvp_reg_index_of_frm1_y_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_DVP_FRM1_ADDR_Y;
		break;
	case 1:
		index = CIF_REG_DVP_FRM1_ADDR_Y_ID1;
		break;
	case 2:
		index = CIF_REG_DVP_FRM1_ADDR_Y_ID2;
		break;
	case 3:
		index = CIF_REG_DVP_FRM1_ADDR_Y_ID3;
		break;
	default:
		index = CIF_REG_DVP_FRM0_ADDR_Y;
		break;
	}

	return index;
}

static enum cif_reg_index get_dvp_reg_index_of_frm0_uv_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_DVP_FRM0_ADDR_UV;
		break;
	case 1:
		index = CIF_REG_DVP_FRM0_ADDR_UV_ID1;
		break;
	case 2:
		index = CIF_REG_DVP_FRM0_ADDR_UV_ID2;
		break;
	case 3:
		index = CIF_REG_DVP_FRM0_ADDR_UV_ID3;
		break;
	default:
		index = CIF_REG_DVP_FRM0_ADDR_UV;
		break;
	}

	return index;
}

static enum cif_reg_index get_dvp_reg_index_of_frm1_uv_addr(int channel_id)
{
	enum cif_reg_index index;

	switch (channel_id) {
	case 0:
		index = CIF_REG_DVP_FRM1_ADDR_UV;
		break;
	case 1:
		index = CIF_REG_DVP_FRM1_ADDR_UV_ID1;
		break;
	case 2:
		index = CIF_REG_DVP_FRM1_ADDR_UV_ID2;
		break;
	case 3:
		index = CIF_REG_DVP_FRM1_ADDR_UV_ID3;
		break;
	default:
		index = CIF_REG_DVP_FRM1_ADDR_UV;
		break;
	}

	return index;
}

static unsigned char get_data_type(u32 pixelformat, u8 cmd_mode_en)
{
	switch (pixelformat) {
	/* csi raw8 */
	case MEDIA_BUS_FMT_SBGGR8_1X8:
	case MEDIA_BUS_FMT_SGBRG8_1X8:
	case MEDIA_BUS_FMT_SGRBG8_1X8:
	case MEDIA_BUS_FMT_SRGGB8_1X8:
		return 0x2a;
	/* csi raw10 */
	case MEDIA_BUS_FMT_SBGGR10_1X10:
	case MEDIA_BUS_FMT_SGBRG10_1X10:
	case MEDIA_BUS_FMT_SGRBG10_1X10:
	case MEDIA_BUS_FMT_SRGGB10_1X10:
		return 0x2b;
	/* csi raw12 */
	case MEDIA_BUS_FMT_SBGGR12_1X12:
	case MEDIA_BUS_FMT_SGBRG12_1X12:
	case MEDIA_BUS_FMT_SGRBG12_1X12:
	case MEDIA_BUS_FMT_SRGGB12_1X12:
		return 0x2c;
	/* csi uyvy 422 */
	case MEDIA_BUS_FMT_UYVY8_2X8:
	case MEDIA_BUS_FMT_VYUY8_2X8:
	case MEDIA_BUS_FMT_YUYV8_2X8:
	case MEDIA_BUS_FMT_YVYU8_2X8:
		return 0x1e;
	case MEDIA_BUS_FMT_RGB888_1X24: {
		if (cmd_mode_en) /* dsi command mode*/
			return 0x39;
		else /* dsi video mode */
			return 0x3e;
	}

	default:
		return 0x2b;
	}
}

#define UV_OFFSET (cif->cif_cfg.width * cif->cif_cfg.height)

static int vehicle_cif_init_buffer(struct vehicle_cif *cif,
					     int init, int csi_ch)
{
	struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf;
	u32 frm0_addr_y, frm0_addr_uv;
	u32 frm1_addr_y, frm1_addr_uv;
	unsigned long y_addr, uv_addr;
	int i;

	if (cif->cif_cfg.buf_num < 2)
		return -EINVAL;

	if (cif->cif_cfg.buf_num > MAX_BUF_NUM)
		cif->cif_cfg.buf_num = MAX_BUF_NUM;

	for (i = 0 ; i < cif->cif_cfg.buf_num; i++) {
		cif->frame_buf[i] = cif->cif_cfg.buf_phy_addr[i];
		if (cif->frame_buf[i] == 0)
			return -EINVAL;
	}

	cif->last_buf_index = 0;
	cif->current_buf_index = 1;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		frm0_addr_y = get_reg_index_of_frm0_y_addr(csi_ch);
		frm0_addr_uv = get_reg_index_of_frm0_uv_addr(csi_ch);
		frm1_addr_y = get_reg_index_of_frm1_y_addr(csi_ch);
		frm1_addr_uv = get_reg_index_of_frm1_uv_addr(csi_ch);
	} else {
		frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(csi_ch);
		frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(csi_ch);
		frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(csi_ch);
		frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(csi_ch);
	}

	spin_lock(&cif->vbq_lock);

	y_addr = vehicle_flinger_request_cif_buffer();
	if (y_addr) {
		uv_addr = y_addr + UV_OFFSET;
		rkcif_write_reg(cif, frm0_addr_y, y_addr);
		rkcif_write_reg(cif, frm0_addr_uv, uv_addr);
		cif->active[0] = y_addr;
	} else {
		rkcif_write_reg(cif, frm0_addr_y, dummy_buf->dma_addr);
		rkcif_write_reg(cif, frm0_addr_uv, dummy_buf->dma_addr);
		cif->active[0] = y_addr;
	}

	y_addr = vehicle_flinger_request_cif_buffer();
	if (y_addr) {
		uv_addr = y_addr + UV_OFFSET;
		rkcif_write_reg(cif, frm1_addr_y, y_addr);
		rkcif_write_reg(cif, frm1_addr_uv, uv_addr);
		cif->active[1] = y_addr;
	} else {
		rkcif_write_reg(cif, frm1_addr_y, dummy_buf->dma_addr);
		rkcif_write_reg(cif, frm1_addr_uv, dummy_buf->dma_addr);
		cif->active[1] = y_addr;
	}

	if (cif->cif_cfg.type != V4L2_MBUS_CSI2_DPHY) {
		int ch_id;

		for (ch_id = 0; ch_id < 4; ch_id++) {
			if (ch_id == csi_ch)
				continue;

			rkcif_write_reg(cif, get_dvp_reg_index_of_frm0_y_addr(ch_id),
					dummy_buf->dma_addr);
			rkcif_write_reg(cif, get_dvp_reg_index_of_frm1_y_addr(ch_id),
					dummy_buf->dma_addr);
			rkcif_write_reg(cif, get_dvp_reg_index_of_frm0_uv_addr(ch_id),
					dummy_buf->dma_addr);
			rkcif_write_reg(cif, get_dvp_reg_index_of_frm1_uv_addr(ch_id),
					dummy_buf->dma_addr);
		}
	}

	spin_unlock(&cif->vbq_lock);

	return 0;
}

static int vehicle_cif_csi_channel_init(struct vehicle_cif *cif,
		   struct vehicle_csi_channel_info *channel)
{
	struct vehicle_cfg *cfg = &cif->cif_cfg;
	const struct cif_output_fmt *fmt;
	u32 fourcc;

	channel->enable = 1;
	channel->width = cfg->width;
	channel->height = cfg->height;
	cif->interlaced_enable = false;
	channel->cmd_mode_en = 0; /* default use DSI Video Mode */

	channel->crop_en = 1;
	channel->crop_st_x = cfg->start_x;
	channel->crop_st_y = cfg->start_y;
	channel->width = cfg->width;
	channel->height = cfg->height;
	if (cfg->output_format == CIF_OUTPUT_FORMAT_420) {
		fmt = find_output_fmt(V4L2_PIX_FMT_NV12);
		if (!fmt) {
			VEHICLE_DGERR("can not find output format: 0x%x", V4L2_PIX_FMT_NV12);
			return -EINVAL;
		}
	} else {
		fmt = find_output_fmt(V4L2_PIX_FMT_NV16);
		if (!fmt) {
			VEHICLE_DGERR("can not find output format: 0x%x", V4L2_PIX_FMT_NV16);
			return -EINVAL;
		}
	}

	channel->fmt_val = fmt->csi_fmt_val;
	VEHICLE_INFO("%s, LINE=%d, channel->fmt_val = 0x%x, fmt->csi_fmt_val= 0x%x",
				__func__, __LINE__, channel->fmt_val, fmt->csi_fmt_val);
	/*
	 * for mipi or lvds, when enable compact, the virtual width of raw10/raw12
	 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode
	 * needs aligned with :ALIGN(bits_per_pixel * width * 2, 8), to optimize reading and
	 * writing of ddr, aligned with 256
	 */

	if (fmt->fmt_type == CIF_FMT_TYPE_RAW && channel->fmt_val != CSI_WRDDR_TYPE_RAW8)
		channel->virtual_width = ALIGN(channel->width * 2, 8);
	else
		channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);

	if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
		channel->width = channel->width * fmt->bpp[0] / 8;
	/*
	 * rk cif don't support output yuyv fmt data
	 * if user request yuyv fmt, the input mode must be RAW8
	 * and the width is double Because the real input fmt is
	 * yuyv
	 */
	fourcc = fmt->fourcc;
	if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU ||
	    fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY) {
		channel->fmt_val = CSI_WRDDR_TYPE_RAW8;
		channel->width *= 2;
		channel->virtual_width *= 2;
	}
	VEHICLE_DG("%s, LINE=%d, channel->fmt_val = 0x%x", __func__, __LINE__, channel->fmt_val);
	if (cfg->input_format == CIF_INPUT_FORMAT_PAL ||
		cfg->input_format == CIF_INPUT_FORMAT_NTSC) {
		VEHICLE_INFO("CVBS IN PAL or NTSC config.");
		cif->interlaced_enable = true;
		if (!cif->use_hw_interlace) {
			channel->virtual_width *= 2;
			cif->interlaced_offset = channel->width;
			cif->interlaced_counts = 0;
			cif->interlaced_buffer = 0;
			channel->height /= 2;
		}

		VEHICLE_INFO("do denterlaced.\n");
	}

	channel->data_type = get_data_type(cfg->mbus_code,
					   channel->cmd_mode_en);

	return 0;
}

static int vehicle_cif_csi_channel_set(struct vehicle_cif *cif,
				       struct vehicle_csi_channel_info *channel,
				       enum v4l2_mbus_type mbus_type)

{
	unsigned int val = 0x0;

	if (channel->id >= 4)
		return -EINVAL;

	if (!channel->enable) {
		rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id),
				CSI_DISABLE_CAPTURE);
		return 0;
	}

	rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTSTAT,
				~(CSI_START_INTSTAT(channel->id) |
				CSI_DMA_END_INTSTAT(channel->id) |
				CSI_LINE_INTSTAT(channel->id)));

	/* 0. need set CIF_CSI_INTEN to 0x0 first */
	rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, 0x0);

	/* enable id0 frame start int for sof(long frame, for hdr)
	 * vehicle don't need this
	 */
	if (channel->id == RKCIF_STREAM_MIPI_ID0)
		rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
					CSI_START_INTEN(channel->id));

	rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
			     0x3fff << 16 | 0x3fff);
	rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
			     0x3fff << 16 | 0x3fff);

	rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
				CSI_DMA_END_INTEN(channel->id));

	rkcif_write_reg(cif, CIF_REG_MIPI_WATER_LINE,
			     CIF_MIPI_LVDS_SW_WATER_LINE_25_RK1808 |
			     CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE_RK1808 |
			     CIF_MIPI_LVDS_SW_HURRY_VALUE_RK1808(0x3) |
			     CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808);

	val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x3) |
		CIF_MIPI_LVDS_SW_PRESS_ENABLE |
		CIF_MIPI_LVDS_SW_HURRY_VALUE(0x3) |
		CIF_MIPI_LVDS_SW_HURRY_ENABLE |
		CIF_MIPI_LVDS_SW_WATER_LINE_25 |
		CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE;

	val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS;

	rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val);

	rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
				CSI_ALL_ERROR_INTEN);

	rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id),
			     channel->width | (channel->height << 16));

	rkcif_write_reg(cif, get_reg_index_of_frm0_y_vlw(channel->id),
			     channel->virtual_width);
	rkcif_write_reg(cif, get_reg_index_of_frm1_y_vlw(channel->id),
			     channel->virtual_width);
	rkcif_write_reg(cif, get_reg_index_of_frm0_uv_vlw(channel->id),
			     channel->virtual_width);
	rkcif_write_reg(cif, get_reg_index_of_frm1_uv_vlw(channel->id),
			     channel->virtual_width);

	if (channel->crop_en)
		rkcif_write_reg(cif, get_reg_index_of_id_crop_start(channel->id),
				     channel->crop_st_y << 16 | channel->crop_st_x);

	return 0;
}

/*config reg for rk3588*/
static int vehicle_cif_csi_channel_set_v1(struct vehicle_cif *cif,
				       struct vehicle_csi_channel_info *channel,
				       enum v4l2_mbus_type mbus_type)
{
	unsigned int val = 0x0;

	if (channel->id >= 4)
		return -EINVAL;

	if (!channel->enable) {
		rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id),
				CSI_DISABLE_CAPTURE);
		return 0;
	}

	rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTSTAT,
				 ~(CSI_START_INTSTAT(channel->id) |
				 CSI_DMA_END_INTSTAT(channel->id) |
				 CSI_LINE_INTSTAT_V1(channel->id)));

	/* enable id0 frame start int for sof(long frame, for hdr)
	 * vehicle don't need this
	 */
	if (channel->id == RKCIF_STREAM_MIPI_ID0)
		rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
					CSI_START_INTEN(channel->id));

	rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
			     0x3fff << 16 | 0x3fff);
	rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
			     0x3fff << 16 | 0x3fff);

	rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
				CSI_DMA_END_INTEN(channel->id));

	if (cif->chip_id > CHIP_RK3562_VEHICLE_CIF) {
		val = CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE |
			(CIF_MIPI_LVDS_SW_WATER_LINE_25 << 19);

		rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val);
	} else {
		val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) |
			CIF_MIPI_LVDS_SW_PRESS_ENABLE |
			CIF_MIPI_LVDS_SW_HURRY_VALUE_RK3588(0x3) |
			CIF_MIPI_LVDS_SW_HURRY_ENABLE |
			CIF_MIPI_LVDS_SW_WATER_LINE_25 |
			CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE;

		rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val);
	}

	rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN,
				CSI_ALL_ERROR_INTEN_V1);

	if (cif->chip_id < CHIP_RK3576_VEHICLE_CIF)
		rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id),
				     (channel->width) | (channel->height << 16));
	else
		rkcif_write_reg(cif, CIF_REG_MIPI_SET_SIZE_ID0 + channel->id,
				     (channel->width) | (channel->height << 16));

	rkcif_write_reg(cif, get_reg_index_of_frm0_y_vlw(channel->id),
			     channel->virtual_width);

	if (channel->crop_en)
		rkcif_write_reg(cif, get_reg_index_of_id_crop_start(channel->id),
				     channel->crop_st_y << 16 | channel->crop_st_x);

	return 0;
}

static int vehicle_cif_stream_start(struct vehicle_cif *cif)
{
	struct vehicle_csi_channel_info *channel;

	vehicle_cif_csi_get_vc_num(cif);

	/* just need init virtual channel 0 */
	channel = &cif->channels[0];
	channel->id = 0;
	vehicle_cif_csi_channel_init(cif, channel);
	if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF)
		vehicle_cif_csi_channel_set(cif, channel, V4L2_MBUS_CSI2_DPHY);
	else
		vehicle_cif_csi_channel_set_v1(cif, channel, V4L2_MBUS_CSI2_DPHY);

	return 0;
}

static int cif_csi_stream_setup(struct vehicle_cif *cif)
{
	vehicle_csi2_stream_start(cif);
	if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY)
		vehicle_csi2_dcphy_stream_start(cif);
	else
		vehicle_csi2_dphy_stream_start(cif);
	vehicle_cif_stream_start(cif);

	return 0;
}

static void vehicle_csi2_dphy_hw_do_reset(struct vehicle_cif  *cif)
{
	unsigned int i;
	struct csi2_dphy_hw *dphy_hw = cif->dphy_hw;

	for (i = 0; i < dphy_hw->num_dphy_rsts; i++)
		if (dphy_hw->dphy_rst[i])
			reset_control_assert(dphy_hw->dphy_rst[i]);
	udelay(5);
	for (i = 0; i < dphy_hw->num_dphy_rsts; i++)
		if (dphy_hw->dphy_rst[i])
			reset_control_deassert(dphy_hw->dphy_rst[i]);
}

static void vehicle_csi2_hw_soft_reset(struct vehicle_cif  *cif)
{
	unsigned int i;
	struct csi2_dphy_hw *dphy_hw = cif->dphy_hw;

	for (i = 0; i < dphy_hw->num_csi2_rsts; i++)
		if (dphy_hw->csi2_rst[i])
			reset_control_assert(dphy_hw->csi2_rst[i]);
	udelay(5);
	for (i = 0; i < dphy_hw->num_csi2_rsts; i++)
		if (dphy_hw->csi2_rst[i])
			reset_control_deassert(dphy_hw->csi2_rst[i]);
}

static int vehicle_csi2_dphy_stream_stop(struct vehicle_cif *cif)
{
	struct csi2_dphy_hw *hw = cif->dphy_hw;

	mutex_lock(&hw->mutex);

	write_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, 0x01);
	if (cif->dphy_hw->chip_id >= CHIP_ID_RK3588)
		vehicle_csi2_dphy_hw_do_reset(cif);
	usleep_range(500, 1000);

	mutex_unlock(&hw->mutex);

	return 0;
}

static void vehicle_rkcif_disable_sys_clk(struct rk_cif_clk *clk)
{
	int i;

	for (i = clk->clks_num - 1; i >= 0; i--)
		clk_disable_unprepare(clk->clks[i]);
}

static int vehicle_rkcif_enable_sys_clk(struct rk_cif_clk *clk)
{
	int i, ret = -EINVAL;

	for (i = 0; i < clk->clks_num; i++) {
		ret = clk_prepare_enable(clk->clks[i]);
		if (ret < 0)
			goto err;
	}

	return 0;
err:
	for (--i; i >= 0; --i)
		clk_disable_unprepare(clk->clks[i]);

	return ret;
}

static int rk_cif_mclk_ctrl(struct vehicle_cif *cif, int on)
{
	int err = 0;

	struct rk_cif_clk *clk = &cif->clk;

	if (on && !clk->on) {
		vehicle_rkcif_enable_sys_clk(clk);
		clk->on = true;
	} else if (!on && clk->on) {
		vehicle_rkcif_disable_sys_clk(clk);
		clk->on = false;
	}

	return err;
}

static void csi2_disable_dphy_clk(struct csi2_dphy_hw *hw)
{
	int i;

	for (i = hw->num_dphy_clks - 1; i >= 0; i--) {
		clk_disable_unprepare(hw->dphy_clks[i].clk);
		VEHICLE_INFO("%s(%d) disable dphy clk: %s\n",
			__func__, __LINE__, hw->dphy_clks[i].id);
	}
}

static int csi2_enable_dphy_clk(struct csi2_dphy_hw *hw)
{
	int i, ret = -EINVAL;

	for (i = 0; i < hw->num_dphy_clks; i++) {
		ret = clk_prepare_enable(hw->dphy_clks[i].clk);
		if (ret < 0)
			goto err;
		VEHICLE_INFO("%s(%d) enable dphy clk: %s\n",
			__func__, __LINE__, hw->dphy_clks[i].id);
	}

	return 0;
err:
	VEHICLE_DGERR("%s(%d) enable dphy clk: %s err\n",
			__func__, __LINE__, hw->dphy_clks[i].id);
	for (--i; i >= 0; --i)
		clk_disable_unprepare(hw->dphy_clks[i].clk);

	return ret;
}

static void csi2_disable_clk(struct csi2_dphy_hw *hw)
{
	int i;

	for (i = hw->num_csi2_clks - 1; i >= 0; i--) {
		clk_disable_unprepare(hw->csi2_clks[i].clk);
		VEHICLE_INFO("%s(%d) disable csi2 clk: %s\n",
				__func__, __LINE__, hw->csi2_clks[i].id);
	}
}

static int csi2_enable_clk(struct csi2_dphy_hw *hw)
{
	int i, ret = -EINVAL;

	for (i = 0; i < hw->num_csi2_clks; i++) {
		ret = clk_prepare_enable(hw->csi2_clks[i].clk);
		if (ret < 0)
			goto err;
		VEHICLE_INFO("%s(%d) enable csi2 clk: %s\n",
			__func__, __LINE__, hw->csi2_clks[i].id);
	}

	return 0;
err:
	VEHICLE_DGERR("%s(%d) enable csi2 clk: %s err\n",
			__func__, __LINE__, hw->csi2_clks[i].id);
	for (--i; i >= 0; --i)
		clk_disable_unprepare(hw->csi2_clks[i].clk);

	return ret;
}

static int vehicle_csi2_clk_ctrl(struct vehicle_cif *cif, int on)
{
	int ret = 0;
	struct csi2_dphy_hw *dphy_hw = cif->dphy_hw;

	on = !!on;
	if (on) {
		ret = csi2_enable_dphy_clk(dphy_hw);
		if (ret < 0) {
			VEHICLE_DGERR("enable csi dphy clk failed!");
			goto err;
		}
		ret = csi2_enable_clk(dphy_hw);
		if (ret < 0) {
			VEHICLE_DGERR("enable csi dphy clk failed!");
			goto err;
		}
		dphy_hw->on = true;
	} else {
		csi2_disable_dphy_clk(dphy_hw);
		csi2_disable_clk(dphy_hw);
		dphy_hw->on = false;
	}

	return 0;
err:
	return ret;
}

static int vehicle_csi2_stream_stop(struct vehicle_cif *cif)
{
	vehicle_csi2_disable(cif);

	return 0;
}

static int vehicle_cif_stream_stop(struct vehicle_cif *cif)
{
	return 0;
}

static int vehicle_cif_csi_stream_stop(struct vehicle_cif *cif)
{
	vehicle_cif_stream_stop(cif);
	vehicle_csi2_stream_stop(cif);
	if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY)
		vehicle_csi2_dcphy_stream_stop(cif);
	else
		vehicle_csi2_dphy_stream_stop(cif);

	return 0;
}

static int vehicle_cif_csi2_s_stream(struct vehicle_cif *cif,
				int enable,
				enum v4l2_mbus_type mbus_type)

{
	unsigned int val = 0x0;
	const struct cif_input_fmt *infmt;
	struct vehicle_csi_channel_info *channel;
	int id;

	channel = &cif->channels[0];

	if (enable) {
		val = CSI_ENABLE_CAPTURE | channel->fmt_val |
		      channel->cmd_mode_en << 4 | channel->crop_en << 5 |
		      channel->id << 8 | channel->data_type << 10;

		val &= ~CSI_ENABLE_MIPI_COMPACT;

		infmt = find_input_fmt(cif->cif_cfg.mbus_code);
		if (!infmt) {
			VEHICLE_INFO("Input fmt is invalid, use default!\n");
			val |= CSI_YUV_INPUT_ORDER_UYVY;
		} else {
			val |= infmt->csi_yuv_order;
		}

		rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val);
		cif->state = RKCIF_STATE_STREAMING;
	} else {
		id = channel->id;
		val = rkcif_read_reg(cif, get_reg_index_of_id_ctrl0(id));
		val &= ~CSI_ENABLE_CAPTURE;

		rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(id), val);

		rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTSTAT,
					CSI_START_INTSTAT(id) |
					CSI_DMA_END_INTSTAT(id) |
					CSI_LINE_INTSTAT(id));

		rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN,
					 ~(CSI_START_INTEN(id) |
					   CSI_DMA_END_INTEN(id) |
					   CSI_LINE_INTEN(id)));

		rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN,
					~CSI_ALL_ERROR_INTEN);
		cif->state = RKCIF_STATE_READY;
	}

	return 0;
}

static int vehicle_cif_csi2_s_stream_v1(struct vehicle_cif *cif,
				int enable,
				enum v4l2_mbus_type mbus_type)

{
	unsigned int val = 0x0;
	const struct cif_input_fmt *infmt;
	struct vehicle_csi_channel_info *channel;
	struct vehicle_cfg *cfg = &cif->cif_cfg;
	int id;

	channel = &cif->channels[0];

	if (enable) {
		if (cif->chip_id <= CHIP_RK3562_VEHICLE_CIF) {
			val = CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE |
			      channel->cmd_mode_en << 26 | CSI_ENABLE_CROP_V1 |
			      channel->id << 8 | channel->data_type << 10;

			infmt = find_input_fmt(cif->cif_cfg.mbus_code);
			if (!infmt) {
				VEHICLE_INFO("Input fmt is invalid, use default!\n");
				val |= CSI_YUV_INPUT_ORDER_UYVY;
			} else {
				val |= infmt->csi_yuv_order | infmt->csi_fmt_val;
			}

			if (cfg->output_format == CIF_OUTPUT_FORMAT_420) {
				if (find_output_fmt(V4L2_PIX_FMT_NV12))
					val |= CSI_WRDDR_TYPE_YUV420SP_RK3588 |
						CSI_YUV_OUTPUT_ORDER_UYVY;
			} else {
				if (find_output_fmt(V4L2_PIX_FMT_NV16))
					val |= CSI_WRDDR_TYPE_YUV422SP_RK3588 |
						CSI_YUV_OUTPUT_ORDER_UYVY;
			}

			rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val);
		} else {
			val = CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576 |
			      CSI_ENABLE_CROP_RK3576;

			infmt = find_input_fmt(cif->cif_cfg.mbus_code);
			if (!infmt) {
				VEHICLE_INFO("Input fmt is invalid, use default!\n");
				val |= CSI_YUV_INPUT_ORDER_UYVY;
			} else if (cif->interlaced_enable) {
				val |= (infmt->csi_yuv_order >> 4) |
						((infmt->csi_fmt_val + 1) << 4);
			} else {
				val |= (infmt->csi_yuv_order >> 4) | (infmt->csi_fmt_val << 4);
			}

			if (cfg->output_format == CIF_OUTPUT_FORMAT_420) {
				if (find_output_fmt(V4L2_PIX_FMT_NV12))
					val |= CSI_WRDDR_TYPE_YUV420SP_RK3588 << 3 |
						CSI_YUV_OUTPUT_ORDER_UYVY >> 4;
			} else {
				if (find_output_fmt(V4L2_PIX_FMT_NV16))
					val |= CSI_WRDDR_TYPE_YUV422SP_RK3588 << 3 |
						CSI_YUV_OUTPUT_ORDER_UYVY >> 4;
			}

			if (cfg->output_format == CIF_OUTPUT_FORMAT_420)
				val |= CSI_UVDS_EN;
			rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val);

			val = channel->data_type << 2;
			rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id), val);

		}

		rkcif_write_reg(cif, CIF_REG_MIPI_EFFECT_CODE_ID0, 0x02410251);
		rkcif_write_reg(cif, CIF_REG_MIPI_EFFECT_CODE_ID1, 0x02420252);
		cif->state = RKCIF_STATE_STREAMING;
	} else {
		id = channel->id;
		val = rkcif_read_reg(cif, get_reg_index_of_id_ctrl0(id));
		if (cif->chip_id >= CHIP_RK3576_VEHICLE_CIF)
			val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576);
		else
			val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE);

		rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(id), val);

		rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTSTAT,
					CSI_START_INTSTAT(id) |
					CSI_DMA_END_INTSTAT(id) |
					CSI_LINE_INTSTAT(id));

		rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN,
					 ~(CSI_START_INTEN(id) |
					   CSI_DMA_END_INTEN(id) |
					   CSI_LINE_INTEN(id)));

		rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN,
					~CSI_ALL_ERROR_INTEN_V1);
		rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_CTRL,
						~CSI_ENABLE_CAPTURE);
		cif->state = RKCIF_STATE_READY;
	}

	return 0;
}

static int cif_interrupt_setup(struct vehicle_cif *cif)
{
	rkcif_write_reg(cif, CIF_REG_DVP_INTEN,
			     FRAME_END_EN | INTSTAT_ERR |
			     PST_INF_FRAME_END);

	/* enable line int for sof */
	rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1);
	rkcif_write_reg(cif, CIF_REG_DVP_INTEN, LINE_INT_EN);

	return 0;
}

static void vehicle_cif_dvp_dump_regs(struct vehicle_cif *cif)
{
	int val;

	if (!vehicle_debug)
		return;

	val = rkcif_read_reg(cif, CIF_REG_DVP_CTRL);
	VEHICLE_DG("CIF_REG_DVP_CTRL = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
	VEHICLE_DG("CIF_REG_DVP_INTEN = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT);
	VEHICLE_DG("CIF_REG_DVP_INTSTAT = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FOR);
	VEHICLE_DG("CIF_REG_DVP_FOR = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_MULTI_ID);
	VEHICLE_DG("CIF_REG_DVP_MULTI_ID = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_NUM_ADDR);
	VEHICLE_DG("CIF_REG_DVP_LINE_NUM_ADDR = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y);
	VEHICLE_DG("CIF_REG_DVP_FRM0_ADDR_Y = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV);
	VEHICLE_DG("CIF_REG_DVP_FRM0_ADDR_UV = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y);
	VEHICLE_DG("CIF_REG_DVP_FRM1_ADDR_Y = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV);
	VEHICLE_DG("CIF_REG_DVP_FRM1_ADDR_UV = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH);
	VEHICLE_DG("CIF_REG_DVP_VIR_LINE_WIDTH = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_SET_SIZE);
	VEHICLE_DG("CIF_REG_DVP_SET_SIZE = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_INT_NUM);
	VEHICLE_DG("CIF_REG_DVP_LINE_INT_NUM = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_CNT);
	VEHICLE_DG("CIF_REG_DVP_LINE_CNT = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_CROP);
	VEHICLE_DG("CIF_REG_DVP_CROP = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_SCL_CTRL);
	VEHICLE_DG("CIF_REG_DVP_SCL_CTRL = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_FRAME_STATUS);
	VEHICLE_DG("CIF_REG_DVP_FRAME_STATUS = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_CUR_DST);
	VEHICLE_DG("CIF_REG_DVP_CUR_DST = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LAST_LINE);
	VEHICLE_DG("CIF_REG_DVP_LAST_LINE = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LAST_PIX);
	VEHICLE_DG("CIF_REG_DVP_LAST_PIX = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_SCL_VALID_NUM);
	VEHICLE_DG("CIF_REG_DVP_SCL_VALID_NUM = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_NUM_ADDR);
	VEHICLE_DG("CIF_REG_DVP_LINE_NUM_ADDR = 0X%x\r\n", val);

	/* read dvp clk sample edge */
	val = rkvehicle_cif_read_grf_reg(cif, CIF_REG_GRF_CIFIO_CON);
	VEHICLE_DG("CIF_REG_GRF_CIFIO_CON = 0X%x\r\n", val);
}

static void vehicle_cif_csi2_dump_regs(struct vehicle_cif *cif)
{
	int val = 0;
	void __iomem *csi2_base = cif->csi2_base;
	struct csi2_dphy_hw *hw = cif->dphy_hw;

	if (!vehicle_debug)
		return;

	/* 1. dump csi2-dphy regs */
	if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) {
		VEHICLE_DG("\n\n DUMP CSI-DPHY REGS: \r\n");
		read_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, &val);
		VEHICLE_DG("CSI2PHY_REG_CTRL_LANE_ENABLE = 0x%x\r\n", val);

		read_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, &val);
		VEHICLE_DG("CSI2PHY_DUAL_CLK_EN = 0x%x\r\n", val);

		val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_FORCERXMODE);
		VEHICLE_DG("GRF_DPHY_CSI2PHY_FORCERXMODE = 0x%x\r\n", val);

		val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL);
		VEHICLE_DG("GRF_DPHY_CSI2PHY_LANE_SEL = 0x%x\r\n", val);

		val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN);
		VEHICLE_DG("GRF_DPHY_CSI2PHY_DATALANE_EN = 0x%x\r\n", val);

		val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN);
		VEHICLE_DG("GRF_DPHY_CSI2PHY_CLKLANE_EN = 0x%x\r\n", val);
	}

	/* 2. dump csi2 regs */
	VEHICLE_DG("\n\n DUMP CSI2 REGS: \r\n");
	val = vehicle_read_csihost_reg(csi2_base, CSIHOST_N_LANES);
	VEHICLE_DG("CSIHOST_N_LANES = 0x%x\r\n", val);

	val = vehicle_read_csihost_reg(csi2_base, CSIHOST_CONTROL);
	VEHICLE_DG("CSIHOST_CONTROL = 0x%x\r\n", val);

	val = vehicle_read_csihost_reg(csi2_base, CSIHOST_MSK1);
	VEHICLE_DG("CSIHOST_MSK1 = 0x%x\r\n", val);

	val = vehicle_read_csihost_reg(csi2_base, CSIHOST_MSK2);
	VEHICLE_DG("CSIHOST_MSK2 = 0x%x\r\n", val);

	val = vehicle_read_csihost_reg(csi2_base, CSIHOST_RESETN);
	VEHICLE_DG("CSIHOST_RESETN = 0x%x\r\n", val);

	/* 3. dump cif regs */
	VEHICLE_DG("\n\n DUMP MIPI CIF REGS: \r\n");
	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_CTRL);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_CTRL = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTEN);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_INTEN = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_INTSTAT = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CTRL0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CTRL0 = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CTRL1);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CTRL1 = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1 = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3 = 0x%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0 = 0X%x\r\n", val);

	val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CROP_START);
	VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CROP_START = 0X%x\r\n", val);

	/* read dvp clk sample edge */
	val = rkvehicle_cif_read_grf_reg(cif, CIF_REG_GRF_CIFIO_CON);
	VEHICLE_DG("CIF_REG_GRF_CIFIO_CON = 0X%x\r\n", val);
}

static int vehicle_cif_s_stream(struct vehicle_cif *cif, int enable)
{
	int cif_ctrl_val;
	unsigned int dma_en = 0;

	cif->is_enabled = enable;

	VEHICLE_INFO("%s enable=%d\n", __func__, enable);

	if (enable) {
		cif->irqinfo.cifirq_idx = 0;
		cif->irqinfo.cifirq_normal_idx = 0;
		cif->irqinfo.cifirq_abnormal_idx = 0;
		cif->irqinfo.dmairq_idx = 0;
		cif->irqinfo.all_err_cnt = 0;
		cif->irqinfo.dvp_bus_err_cnt = 0;
		cif->irqinfo.dvp_overflow_cnt = 0;
		cif->irqinfo.dvp_pix_err_cnt = 0;
		cif->irqinfo.dvp_line_err_cnt = 0;
		cif->irqinfo.dvp_size_err_cnt = 0;
		cif->irqinfo.dvp_bwidth_lack_cnt = 0;
		cif->irqinfo.csi_size_err_cnt = 0;

		rkcif_write_reg(cif, CIF_REG_DVP_INTEN,
				FRAME_END_EN | INTSTAT_ERR |
				PST_INF_FRAME_END);

		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1);
			rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x033ffff);
		}

		dma_en = DVP_DMA_EN;
		if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) {
			rkcif_write_reg(cif, CIF_REG_DVP_CTRL,
				AXI_BURST_16 | MODE_PINGPONG | ENABLE_CAPTURE);
		} else if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			rkcif_write_reg(cif, CIF_REG_DVP_CTRL,
			     DVP_SW_WATER_LINE_25
			     | dma_en
			     | DVP_PRESS_EN
			     | DVP_HURRY_EN
			     | DVP_SW_WATER_LINE_25
			     | DVP_SW_PRESS_VALUE(3)
			     | DVP_SW_HURRY_VALUE(3)
			     | ENABLE_CAPTURE);
		} else {
			dma_en = DVP_SW_DMA_EN_RK3676(0);
			rkcif_write_reg(cif, CIF_REG_DVP_CTRL,
			     DVP_SW_WATER_LINE_25_RK3576
			     | DVP_SW_CAP_EN_RK3576(0)
			     | dma_en
			     | ENABLE_CAPTURE);
		}

		cif->frame_idx = 0;
		cif->state = RKCIF_STATE_STREAMING;
	} else {
		cif_ctrl_val = rkcif_read_reg(cif, CIF_REG_DVP_CTRL);
		cif_ctrl_val &= ~ENABLE_CAPTURE;
		rkcif_write_reg(cif, CIF_REG_DVP_CTRL, cif_ctrl_val);
		rkcif_write_reg(cif, CIF_REG_DVP_INTEN, 0);
		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3ff);
		rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS, 0x0);
		cif->state = RKCIF_STATE_READY;
	}

	return 0;
}

static int vehicle_cif_create_dummy_buf(struct vehicle_cif *cif)
{
	struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf;
	struct vehicle_cfg *cfg = &cif->cif_cfg;

	/* get a maximum plane size */
	dummy_buf->size = cfg->width * cfg->height * 2;

	dummy_buf->vaddr = dma_alloc_coherent(cif->dev, dummy_buf->size,
					      &dummy_buf->dma_addr,
					      GFP_KERNEL);
	if (!dummy_buf->vaddr) {
		VEHICLE_DGERR("Failed to allocate the memory for dummy buffer\n");
		return -ENOMEM;
	}

	VEHICLE_INFO("Allocate dummy buffer, size: 0x%08x\n", dummy_buf->size);

	return 0;
}

static void vehicle_cif_destroy_dummy_buf(struct vehicle_cif *cif)
{
	struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf;

	VEHICLE_INFO("Destroy dummy buffer, size: 0x%08x\n", dummy_buf->size);

	if (dummy_buf->vaddr)
		dma_free_coherent(cif->dev, dummy_buf->size,
				  dummy_buf->vaddr, dummy_buf->dma_addr);
	dummy_buf->dma_addr = 0;
	dummy_buf->vaddr = NULL;
}

static void vehicle_cif_hw_soft_reset(struct vehicle_cif  *cif)
{
	unsigned int i;
	struct rk_cif_clk *clk = &cif->clk;

	for (i = 0; i < clk->rsts_num; i++)
		if (clk->cif_rst[i])
			reset_control_assert(clk->cif_rst[i]);
	udelay(10);
	for (i = 0; i < clk->rsts_num; i++)
		if (clk->cif_rst[i])
			reset_control_deassert(clk->cif_rst[i]);
}

static void vehicle_rkcif_do_soft_reset(struct vehicle_cif  *cif)
{
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY)
		rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000);
	else
		rkcif_write_reg_or(cif, CIF_REG_DVP_CTRL, 0x000A0000);
	usleep_range(10, 20);
	VEHICLE_INFO("vicap do soft reset 0x%x\n", 0x000A0000);
}

static int vehicle_cif_do_stop_stream(struct vehicle_cif  *cif)
{
	if (!cif)
		return -1;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) {
			vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY);
			vehicle_cif_csi_stream_stop(cif);
		} else {
			vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY);
			vehicle_cif_csi_stream_stop(cif);
		}
	} else {
		vehicle_cif_s_stream(cif, 0);
	}
	if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF)
		vehicle_rkcif_do_soft_reset(cif);
	vehicle_cif_destroy_dummy_buf(cif);

	return 0;
}

static int vehicle_cif_do_start_stream(struct vehicle_cif  *cif)
{
	int ret = 0;

	if (!cif)
		return -ENODEV;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {

		/*  1. stream setup */
		cif_csi_stream_setup(cif);

		/*  2. create dummy buf */
		ret = vehicle_cif_create_dummy_buf(cif);
		if (ret < 0)
			VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret);

		/*  3. cif init buffer */
		if (vehicle_cif_init_buffer(cif, 1, cif->channels[0].id) < 0)
			return -EINVAL;

		/*  4. dump cif regs */
		vehicle_cif_csi2_dump_regs(cif);

		/*  5. start stream */
		if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF)
			vehicle_cif_csi2_s_stream_v1(cif, 1, V4L2_MBUS_CSI2_DPHY);
		else
			vehicle_cif_csi2_s_stream(cif, 1, V4L2_MBUS_CSI2_DPHY);

	} else {
		/*  1. stream setup */
		cif_stream_setup(cif);

		/*  2. create dummy buf */
		ret = vehicle_cif_create_dummy_buf(cif);
		if (ret < 0)
			VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret);

		/*  3. cif init buffer */
		if (vehicle_cif_init_buffer(cif, 1, 0) < 0)
			return -EINVAL;

		/*  4. enable interrupts */
		if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF)
			cif_interrupt_setup(cif);

		/*  5. dump cif regs */
		vehicle_cif_dvp_dump_regs(cif);

		/*  6. start stream */
		vehicle_cif_s_stream(cif, 1);
	}

	return 0;
}

static void vehicle_rkcif_disable_sys_clk(struct rk_cif_clk *clk);
static int vehicle_rkcif_enable_sys_clk(struct rk_cif_clk *clk);

static void vehicle_cif_reset(struct vehicle_cif  *cif, int only_rst)
{
	int ret = 0;

	mutex_lock(&cif->stream_lock);
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		VEHICLE_DG("%s enter, V4L2_MBUS_CSI2 reset need to do!\n", __func__);

		// goto unlock_reset;
		if (only_rst == 1) {
			vehicle_cif_hw_soft_reset(cif);
		} else {
			vehicle_cif_do_stop_stream(cif);
			vehicle_cif_hw_soft_reset(cif);
			vehicle_cif_do_start_stream(cif);
		}
	} else {
		int ctrl_reg, inten_reg, crop_reg, set_size_reg, for_reg;
		int vir_line_width_reg, scl_reg;
		int y0_reg, uv0_reg, y1_reg, uv1_reg;

		VEHICLE_DG("%s enter, do reset!\n", __func__);
		if (only_rst == 1) {
			vehicle_cif_hw_soft_reset(cif);
		} else {
			ctrl_reg = rkcif_read_reg(cif, CIF_REG_DVP_CTRL);
			if (ctrl_reg & ENABLE_CAPTURE)
				rkcif_write_reg(cif, CIF_REG_DVP_CTRL,
					      ctrl_reg & ~ENABLE_CAPTURE);

			crop_reg = rkcif_read_reg(cif, CIF_REG_DVP_CROP);
			set_size_reg = rkcif_read_reg(cif, CIF_REG_DVP_SET_SIZE);
			inten_reg = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
			for_reg = rkcif_read_reg(cif, CIF_REG_DVP_FOR);
			vir_line_width_reg = rkcif_read_reg(cif,
							  CIF_REG_DVP_VIR_LINE_WIDTH);
			scl_reg = rkcif_read_reg(cif, CIF_REG_DVP_SCL_CTRL);
			y0_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y);
			uv0_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV);
			y1_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y);
			uv1_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV);

			udelay(20);
			vehicle_cif_hw_soft_reset(cif);
			vehicle_rkcif_disable_sys_clk(&cif->clk);
			udelay(5);
			ret = vehicle_rkcif_enable_sys_clk(&cif->clk);
			if (ret < 0) {
				VEHICLE_DGERR("@%s, resume cif clk failed!\n", __func__);
				goto unlock_reset;
			}

			rkcif_write_reg(cif, CIF_REG_DVP_CTRL,
				      ctrl_reg & ~ENABLE_CAPTURE);
			rkcif_write_reg(cif, CIF_REG_DVP_INTEN, inten_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_CROP, crop_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_SET_SIZE, set_size_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_FOR, for_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH,
				      vir_line_width_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_SCL_CTRL, scl_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y, y0_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV, uv0_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y, y1_reg);
			rkcif_write_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV, uv1_reg);
		}
	}
unlock_reset:
	mutex_unlock(&cif->stream_lock);
}

static void vehicle_cif_reset_delay(struct vehicle_cif *cif)
{
	mdelay(10);
	vehicle_cif_reset(cif, 0);
	mdelay(10);
	vehicle_cif_s_stream(cif, 1);
}

static void cif_capture_en(char *reg, int enable)
{
	int val = 0;

	val = read_reg(reg, CIF_REG_DVP_CTRL);
	if (enable == 1)
		write_reg(reg, CIF_REG_DVP_CTRL, val | ENABLE_CAPTURE);
	else
		write_reg(reg, CIF_REG_DVP_CTRL, val & (~ENABLE_CAPTURE));
}

static void vehicle_cif_reset_work_func(struct work_struct *work)
{
	struct vehicle_cif *cif = container_of(work, struct vehicle_cif,
			work.work);

	if (cif->stopping)
		return;

	atomic_set(&cif->reset_status, 1);
	vehicle_cif_reset_delay(cif);
	atomic_set(&cif->reset_status, 0);
	wake_up(&cif->wq_stopped);
}

int vehicle_wait_cif_reset_done(void)
{
	struct vehicle_cif *cif = g_cif;
	int ret = 0, retry = 2;

	for (retry = 2; retry >= 0; retry--) {
		ret = wait_event_timeout(cif->wq_stopped,
				   !atomic_read(&cif->reset_status),
				   msecs_to_jiffies(200));
		if (!ret) {
			VEHICLE_DG("%s wait cif reset timeout, left try times(%d)!\n",
				__func__, retry);
		} else {
			break;
		}
	}

	return 0;
}

static int cif_irq_error_process(struct vehicle_cif *cif, unsigned int reg_intstat)
{
	VEHICLE_DG("%s cif->irqinfo.all_err_cnt(%lld)\n", __func__,
					cif->irqinfo.all_err_cnt);
	if (reg_intstat & INTSTAT_ERR) {
		cif->irqinfo.all_err_cnt++;

		if (reg_intstat & BUS_ERR) {
			cif->irqinfo.dvp_bus_err_cnt++;
			VEHICLE_DGERR("dvp bus err\n");
		}

		if (reg_intstat & DVP_ALL_OVERFLOW) {
			cif->irqinfo.dvp_overflow_cnt++;
			VEHICLE_DGERR("dvp overflow err\n");
		}

		if (reg_intstat & LINE_ERR) {
			cif->irqinfo.dvp_line_err_cnt++;
			VEHICLE_DGERR("dvp line err\n");
		}

		if (reg_intstat & PIX_ERR) {
			cif->irqinfo.dvp_pix_err_cnt++;
			VEHICLE_DGERR("dvp pix err\n");
		}

		if (cif->irqinfo.all_err_cnt < 10) {
			u32 mask;

			VEHICLE_DGERR("ERROR: DVP_ALL_ERROR:0x%x!!\n", reg_intstat);
			mask = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
			mask &= ~INTSTAT_ERR;
			rkcif_write_reg(cif, CIF_REG_DVP_INTEN, mask);
			return -2;
		} else if (cif->irqinfo.all_err_cnt >= 10) {
			u32 mask;

			mask = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
			mask &= ~INTSTAT_ERR;
			rkcif_write_reg(cif, CIF_REG_DVP_INTEN, mask);
			VEHICLE_DGERR("ERROR: DVP_ALL_ERROR:0x%x!!\n", reg_intstat);
			return -2;
		}
	}

	return 0;
}

static int vehicle_cif_csi2_g_mipi_id(unsigned int intstat)
{
	if (intstat & CSI_FRAME_END_ID0) {
		if ((intstat & CSI_FRAME_END_ID0) == CSI_FRAME_END_ID0)
			VEHICLE_DG("frame0/1 trigger simultaneously in ID0\n");
		return RKCIF_STREAM_MIPI_ID0;
	}

	if (intstat & CSI_FRAME_END_ID1) {
		if ((intstat & CSI_FRAME_END_ID1) == CSI_FRAME_END_ID1)
			VEHICLE_DG("frame0/1 trigger simultaneously in ID1\n");
		return RKCIF_STREAM_MIPI_ID1;
	}

	if (intstat & CSI_FRAME_END_ID2) {
		if ((intstat & CSI_FRAME_END_ID2) == CSI_FRAME_END_ID2)
			VEHICLE_DG("frame0/1 trigger simultaneously in ID2\n");
		return RKCIF_STREAM_MIPI_ID2;
	}

	if (intstat & CSI_FRAME_END_ID3) {
		if ((intstat & CSI_FRAME_END_ID3) == CSI_FRAME_END_ID3)
			VEHICLE_DG("frame0/1 trigger simultaneously in ID3\n");
		return RKCIF_STREAM_MIPI_ID3;
	}

	return -EINVAL;
}

static __maybe_unused int rkcif_dvp_g_ch_id_by_fe(unsigned int intstat)
{
	if (intstat & DVP_ALL_END_ID0) {
		if ((intstat & DVP_ALL_END_ID0) ==
		    DVP_ALL_END_ID0)
			VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID0\n");
		return RKCIF_STREAM_MIPI_ID0;
	}

	if (intstat & DVP_ALL_END_ID1) {
		if ((intstat & DVP_ALL_END_ID1) ==
		    DVP_ALL_END_ID1)
			VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID1\n");
		return RKCIF_STREAM_MIPI_ID1;
	}

	if (intstat & DVP_ALL_END_ID2) {
		if ((intstat & DVP_ALL_END_ID2) ==
		    DVP_ALL_END_ID2)
			VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID2\n");
		return RKCIF_STREAM_MIPI_ID2;
	}

	if (intstat & DVP_ALL_END_ID3) {
		if ((intstat & DVP_ALL_END_ID3) ==
		    DVP_ALL_END_ID3)
			VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID3\n");
		return RKCIF_STREAM_MIPI_ID3;
	}

	return -EINVAL;
}

static int vehicle_cif_next_buffer(struct vehicle_cif *cif, u32 frame_ready, int mipi_id)
{
	u32 frm0_addr_y, frm0_addr_uv;
	u32 frm1_addr_y, frm1_addr_uv;
	unsigned long y_addr = 0, uv_addr = 0;
	static unsigned long temp_y_addr, temp_uv_addr;
	int commit_buf = 0;
	struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf;
	u32 frm_num_reg, frame_id = 0;
	VEHICLE_DG("@%s, enter, mipi_id(%d)\n", __func__, mipi_id);

	if ((frame_ready > 1) || (cif->cif_cfg.buf_num < 2) ||
		(cif->cif_cfg.buf_num > MAX_BUF_NUM))
		return 0;

	cif->last_buf_index = cif->current_buf_index;
	cif->current_buf_index = (cif->current_buf_index + 1) %
				 cif->cif_cfg.buf_num;

	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		frm0_addr_y = get_reg_index_of_frm0_y_addr(mipi_id);
		frm0_addr_uv = get_reg_index_of_frm0_uv_addr(mipi_id);
		frm1_addr_y = get_reg_index_of_frm1_y_addr(mipi_id);
		frm1_addr_uv = get_reg_index_of_frm1_uv_addr(mipi_id);
		frm_num_reg = get_reg_index_of_frm_num(mipi_id);
		frame_id = rkcif_read_reg(cif, frm_num_reg);
		VEHICLE_DG("@%s, frm_num_reg(0x%x), frame_id:0x%x\n", __func__,
			   frm_num_reg, frame_id);
	} else {
		frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(mipi_id);
		frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(mipi_id);
		frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(mipi_id);
		frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(mipi_id);
	}

	spin_lock(&cif->vbq_lock);

	if (!cif->interlaced_enable || cif->use_hw_interlace) {
		temp_y_addr = vehicle_flinger_request_cif_buffer();
		if (temp_y_addr == 0) {
			VEHICLE_INFO("%s,warnning request buffer failed\n", __func__);
			spin_unlock(&cif->vbq_lock);
			if (dummy_buf->vaddr) {
				if (frame_ready == 0) {
					rkcif_write_reg(cif, frm0_addr_y, dummy_buf->dma_addr);
					rkcif_write_reg(cif, frm0_addr_uv, dummy_buf->dma_addr);
				} else {
					rkcif_write_reg(cif, frm1_addr_y, dummy_buf->dma_addr);
					rkcif_write_reg(cif, frm1_addr_uv, dummy_buf->dma_addr);
				}
				VEHICLE_INFO("frame Drop to dummy buf\n");
			} else {
				VEHICLE_INFO("dummy buf is null!\n");
			}
			return -1;
		}
		temp_uv_addr = temp_y_addr + UV_OFFSET;
		y_addr = temp_y_addr;
		uv_addr = temp_uv_addr;
		commit_buf = 0;
	} else if (cif->interlaced_enable && !cif->use_hw_interlace) {
		if ((frame_id != 0 && (frame_id & 0xffff) % 2 == 0) ||
		    (frame_id == 0 && (cif->interlaced_counts % 2 == 0))) {
			temp_y_addr = vehicle_flinger_request_cif_buffer();
			if (temp_y_addr == 0) {
				VEHICLE_DGERR("%s,warnning request buffer failed\n", __func__);
				spin_unlock(&cif->vbq_lock);
				return -1;
			}
			temp_uv_addr = temp_y_addr + UV_OFFSET;
			y_addr = temp_y_addr;
			uv_addr = temp_uv_addr;
			commit_buf = -1; //not ok yet
		} else {
			y_addr = temp_y_addr + cif->interlaced_offset;
			//uv_addr = temp_uv_addr;
			uv_addr = temp_uv_addr + cif->interlaced_offset;
			commit_buf = 0; //even & odd field add
			if (temp_y_addr == 0) {
				VEHICLE_DGERR("%s,warnning temp_y_addr is NULL!\n", __func__);
				spin_unlock(&cif->vbq_lock);
				return -1;
			}
		}
		WARN_ON(y_addr == cif->interlaced_offset);
		WARN_ON(uv_addr == cif->interlaced_offset);
	}

	if (frame_ready == 0) {
		rkcif_write_reg(cif, frm0_addr_y, y_addr);
		rkcif_write_reg(cif, frm0_addr_uv, uv_addr);
		cif->active[0] = temp_y_addr;
	} else {
		rkcif_write_reg(cif, frm1_addr_y, y_addr);
		rkcif_write_reg(cif, frm1_addr_uv, uv_addr);
		cif->active[1] = temp_y_addr;
	}
	cif->interlaced_counts++;
	spin_unlock(&cif->vbq_lock);

	return commit_buf;
}

/***************************** irq operation ******************************/
//discard the first few frames to solve display abnormality after different model camera switch
static int drop_frames_number;
static irqreturn_t rk_camera_irq(int irq, void *data)
{
	struct vehicle_cif *cif = (struct vehicle_cif *)data;
	u32 lastline, lastpix, ctl;
	u32 cif_frmst, frmid, int_en;
	unsigned int intstat, i = 0xff;
	int frame_ready = 0;
	int frame_phase = 0;
	unsigned long addr;
	int mipi_id = 0;

	if (drop_frames_number > 0) {
		VEHICLE_INFO("%s discard the first few frames!\n", __func__);
		drop_frames_number--;
		goto IRQ_EXIT;
	}

	VEHICLE_DG("%s enter, cifirq_normal_idx(%ld) cif->frame_idx(%d)!\n", __func__,
					cif->irqinfo.cifirq_normal_idx, cif->frame_idx);
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		if (!cif->stopping) {
			if (cif->irqinfo.cifirq_normal_idx == cif->frame_idx) {
				cif->irqinfo.cifirq_abnormal_idx++;
			} else {
				cif->irqinfo.cifirq_normal_idx = cif->frame_idx;
				cif->irqinfo.cifirq_abnormal_idx = 0;
			}
		}

		intstat = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT);
		lastline = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1);

		/* clear all interrupts that has been triggered */
		rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT, intstat);

		/* when not detect new FRAME_END continue over 5 irq, reset, it's abnormal */
		if (cif->irqinfo.cifirq_abnormal_idx >= 5) {
			VEHICLE_DGERR(
			 "ERROR: cifirq_abnormal_idx reach(%ld) consecutive, do reset work!!\n",
			  cif->irqinfo.cifirq_abnormal_idx);
//			mod_delayed_work(system_wq, &cif->work,
//					 msecs_to_jiffies(1));
			cif->irqinfo.cifirq_abnormal_idx = 0;
			vehicle_cif_stat_change_notify();
			goto IRQ_EXIT;
		}

		if (intstat & CSI_FIFO_OVERFLOW) {
			cif->irqinfo.csi_overflow_cnt++;
			VEHICLE_DGERR(
				 "ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n",
				  intstat, lastline);
			goto IRQ_EXIT;
		}

		if (intstat & CSI_BANDWIDTH_LACK) {
			cif->irqinfo.csi_bwidth_lack_cnt++;
			VEHICLE_DGERR(
				 "ERROR: csi bandwidth lack, intstat:0x%x!!\n",
				 intstat);
			if (cif->irqinfo.csi_bwidth_lack_cnt >= 5) {
				//do reset work
//				mod_delayed_work(system_wq, &cif->work,
//						 msecs_to_jiffies(1));
			}
			goto IRQ_EXIT;
		}

		if (intstat & CSI_ALL_ERROR_INTEN) {
			cif->irqinfo.all_err_cnt++;
			VEHICLE_DGERR(
				 "ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat);
			goto IRQ_EXIT;
		}

		/* if do not reach frame dma end, return irq */
		mipi_id = vehicle_cif_csi2_g_mipi_id(intstat);
		if (mipi_id < 0)
			goto IRQ_EXIT;

		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
			mipi_id = vehicle_cif_csi2_g_mipi_id(intstat);

			VEHICLE_DG(" i(%d)  mipi_id(%d)\n", i, mipi_id);
			if (mipi_id < 0)
				continue;

			if (cif->stopping) {
				vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY);
				cif->stopping = false;
				wake_up(&cif->wq_stopped);
				continue;
			}

			if (cif->state != RKCIF_STATE_STREAMING)
				continue;

			switch (mipi_id) {
			case RKCIF_STREAM_MIPI_ID0:
				frame_phase = SW_FRM_END_ID0(intstat);
				intstat &= ~CSI_FRAME_END_ID0;
				break;
			case RKCIF_STREAM_MIPI_ID1:
				frame_phase = SW_FRM_END_ID1(intstat);
				intstat &= ~CSI_FRAME_END_ID1;
				break;
			case RKCIF_STREAM_MIPI_ID2:
				frame_phase = SW_FRM_END_ID2(intstat);
				intstat &= ~CSI_FRAME_END_ID2;
				break;
			case RKCIF_STREAM_MIPI_ID3:
				frame_phase = SW_FRM_END_ID3(intstat);
				intstat &= ~CSI_FRAME_END_ID3;
				break;
			}

			if (frame_phase & CIF_CSI_FRAME1_READY)
				frame_ready = 1;
			else if (frame_phase & CIF_CSI_FRAME0_READY)
				frame_ready = 0;

			addr = cif->active[frame_ready];
			if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0)
				VEHICLE_DG("cif_nex_buffer error, do not commit %lx\n", addr);
			else
				vehicle_flinger_commit_cif_buffer(addr);
		}
		cif->frame_idx++;
	} else {
		intstat = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT);
		cif_frmst = rkcif_read_reg(cif, CIF_REG_DVP_FRAME_STATUS);
		lastline = rkcif_read_reg(cif, CIF_REG_DVP_LAST_LINE);
		lastline = CIF_FETCH_Y_LAST_LINE(lastline);
		lastpix = rkcif_read_reg(cif, CIF_REG_DVP_LAST_PIX);
		lastpix =  CIF_FETCH_Y_LAST_LINE(lastpix);
		ctl = rkcif_read_reg(cif, CIF_REG_DVP_CTRL);
		VEHICLE_DG("lastline:%d, lastpix:%d, ctl:%d\n",
					  lastline, lastpix, ctl);

		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, intstat);

		if ((intstat & LINE_INT_END) && !(intstat & (FRAME_END))) {
			if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) {
				if ((intstat & INTSTAT_ERR) == 0x0) {
					int_en = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
					int_en &= ~LINE_INT_EN;
					rkcif_write_reg(cif, CIF_REG_DVP_INTEN, int_en);
				}
			}
		}

		/* 0. error process */
		if (cif_irq_error_process(cif, intstat) < 0) {
			VEHICLE_DGERR("irq error, to do... reset, intstat=%x\n", intstat);
//			mod_delayed_work(system_wq, &cif->work,
//					 msecs_to_jiffies(1));
			vehicle_cif_stat_change_notify();
			goto IRQ_EXIT;
		}

		/* There are two irqs enabled:
		 *	- PST_INF_FRAME_END: cif FIFO is ready,
		 *	  this is prior to FRAME_END
		 *	- FRAME_END: cif has saved frame to memory,
		 *	  a frame ready
		 */
		if ((intstat & PST_INF_FRAME_END)) {
			cif->irqinfo.cifirq_idx++;
			if (cif->stopping) {
			/* To stop CIF ASAP, before FRAME_END irq */
				vehicle_cif_s_stream(cif, 0);
				cif->stopping = false;
				wake_up(&cif->wq_stopped);
				goto IRQ_EXIT;
			}
		}

		if ((intstat & FRAME_END)) {
			int_en = rkcif_read_reg(cif, CIF_REG_DVP_INTEN);
			int_en |= LINE_INT_EN;
			rkcif_write_reg(cif, CIF_REG_DVP_INTEN, int_en);

			if (cif->stopping) {
				vehicle_cif_s_stream(cif, 0);
				cif->stopping = false;
				wake_up(&cif->wq_stopped);
				goto IRQ_EXIT;
			}

			frmid = CIF_GET_FRAME_ID(cif_frmst);
			if ((cif_frmst == 0xfffd0002) || (cif_frmst == 0xfffe0002)) {
				VEHICLE_DG("frmid:%d, frmstat:0x%x\n",
					  frmid, cif_frmst);
				rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS,
							 FRAME_STAT_CLS);
			}

			if ((!(cif_frmst & CIF_F0_READY) && !(cif_frmst & CIF_F1_READY))) {
				VEHICLE_DG("err f0 && f1 not ready\n");
				cif_capture_en(cif->base, 0);
				rkcif_write_reg(cif, CIF_REG_DVP_INTEN, 0);
				mod_delayed_work(system_wq, &cif->work,
						 msecs_to_jiffies(1));
				goto IRQ_EXIT;
			}

			if (cif_frmst & CIF_F0_READY)
				frame_ready = 0;
			else
				frame_ready = 1;
			addr = cif->active[frame_ready];
			if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0)
				CIF_DG("cif_nex_buffer error, do not commit %lx\n", addr);
			else
				vehicle_flinger_commit_cif_buffer(addr);
			cif->frame_idx++;
		}
	}
	cif->irqinfo.all_frm_end_cnt++;

IRQ_EXIT:
	return IRQ_HANDLED;
}

static irqreturn_t rk_camera_irq_v1(int irq, void *data)
{
	struct vehicle_cif *cif = (struct vehicle_cif *)data;
	u32 lastline;
	unsigned int intstat, i = 0xff, bak_intstat = 0;
	int frame_ready = 0;
	int frame_phase = 0;
	unsigned long addr;
	int mipi_id = 0;

	if (drop_frames_number > 0) {
		VEHICLE_INFO("%s discard the first few frames!\n", __func__);
		drop_frames_number--;
		goto IRQ_EXIT;
	}

	VEHICLE_DG("%s enter, cifirq_normal_idx(%ld) cif->frame_idx(%d)!\n", __func__,
					cif->irqinfo.cifirq_normal_idx, cif->frame_idx);
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		if (!cif->stopping) {
			if (cif->irqinfo.cifirq_normal_idx == cif->frame_idx) {
				cif->irqinfo.cifirq_abnormal_idx++;
			} else {
				cif->irqinfo.cifirq_normal_idx = cif->frame_idx;
				cif->irqinfo.cifirq_abnormal_idx = 0;
			}
		}

		intstat = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT);
		lastline = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1);

		/* clear all interrupts that has been triggered */
		if (intstat) {
			bak_intstat = intstat;
			VEHICLE_DG("%s bak_intstat = %d!\n", __func__, bak_intstat);
			rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT, intstat);
		} else {
			goto IRQ_EXIT;
		}

		/* when not detect new FRAME_END continue over 5 irq, reset, it's abnormal */
		if (cif->irqinfo.cifirq_abnormal_idx >= 5) {
			VEHICLE_DGERR(
				"ERROR: cifirq_abnormal_idx reach(%ld) consecutive, do reset work!!\n",
				cif->irqinfo.cifirq_abnormal_idx);
			cif->irqinfo.cifirq_abnormal_idx = 0;
			vehicle_cif_stat_change_notify();
			goto IRQ_EXIT;
		}

		if (intstat & CSI_SIZE_ERR) {
			cif->irqinfo.csi_size_err_cnt++;
			VEHICLE_DGERR("ERROR: csi size error, intstat:0x%x, lastline:%d!!\n",
				intstat, lastline);
			goto IRQ_EXIT;
		}

		if (intstat & CSI_FIFO_OVERFLOW_V1) {
			cif->irqinfo.csi_overflow_cnt++;
			VEHICLE_DGERR("ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n",
				intstat, lastline);
			goto IRQ_EXIT;
		}

		if (intstat & CSI_BANDWIDTH_LACK_V1) {
			cif->irqinfo.csi_bwidth_lack_cnt++;
			VEHICLE_DGERR("ERROR: csi bandwidth lack, intstat:0x%x!!\n",
				intstat);
			goto IRQ_EXIT;
		}

		if (intstat & CSI_ALL_ERROR_INTEN_V1) {
			cif->irqinfo.all_err_cnt++;
			VEHICLE_DGERR("ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat);
			goto IRQ_EXIT;
		}

		/* if do not reach frame dma end, return irq */
		mipi_id = vehicle_cif_csi2_g_mipi_id(intstat);
		if (mipi_id < 0)
			goto IRQ_EXIT;

		for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
			mipi_id = vehicle_cif_csi2_g_mipi_id(intstat);

			VEHICLE_DG(" i(%d)  mipi_id(%d)\n", i, mipi_id);
			if (mipi_id < 0)
				continue;

			if (cif->stopping) {
				vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY);
				cif->stopping = false;
				wake_up(&cif->wq_stopped);
				continue;
			}

			if (cif->state != RKCIF_STATE_STREAMING)
				continue;

			switch (mipi_id) {
			case RKCIF_STREAM_MIPI_ID0:
				frame_phase = SW_FRM_END_ID0(intstat);
				intstat &= ~CSI_FRAME_END_ID0;
				break;
			case RKCIF_STREAM_MIPI_ID1:
				frame_phase = SW_FRM_END_ID1(intstat);
				intstat &= ~CSI_FRAME_END_ID1;
				break;
			case RKCIF_STREAM_MIPI_ID2:
				frame_phase = SW_FRM_END_ID2(intstat);
				intstat &= ~CSI_FRAME_END_ID2;
				break;
			case RKCIF_STREAM_MIPI_ID3:
				frame_phase = SW_FRM_END_ID3(intstat);
				intstat &= ~CSI_FRAME_END_ID3;
				break;
			}

			if (frame_phase & CIF_CSI_FRAME1_READY)
				frame_ready = 1;
			else if (frame_phase & CIF_CSI_FRAME0_READY)
				frame_ready = 0;

			addr = cif->active[frame_ready];
			if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0)
				VEHICLE_DGERR("cif_nex_buffer error, do not commit %lx\n", addr);
			else
				vehicle_flinger_commit_cif_buffer(addr);
		}
		cif->frame_idx++;
	} else {
		int ch_id;

		intstat = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT);

		rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, intstat);

		if (intstat & DVP_SIZE_ERR) {
			cif->irqinfo.dvp_size_err_cnt++;
			VEHICLE_DGERR("dvp size err intstat 0x%x\n", intstat);
		}

		if (intstat & DVP_FIFO_OVERFLOW) {
			cif->irqinfo.dvp_overflow_cnt++;
			VEHICLE_DGERR("dvp fifo overflow err intstat 0x%x\n", intstat);
		}

		if (intstat & DVP_BANDWIDTH_LACK) {
			cif->irqinfo.dvp_bwidth_lack_cnt++;
			VEHICLE_DGERR("dvp bandwidth lack err intstat 0x%x\n", intstat);
		}

		if (intstat & INTSTAT_ERR_RK3588) {
			cif->irqinfo.all_err_cnt++;
			VEHICLE_DGERR("ERROR: DVP_ALL_ERROR_INTEN:0x%x!!\n", intstat);
		}
		for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) {
			ch_id = rkcif_dvp_g_ch_id_by_fe(intstat);

			if (ch_id < 0)
				continue;

			if (cif->stopping) {
				vehicle_cif_s_stream(cif, 0);
				cif->stopping = false;
				wake_up(&cif->wq_stopped);
				continue;
			}

			if (cif->state != RKCIF_STATE_STREAMING)
				continue;

			switch (ch_id) {
			case RKCIF_STREAM_MIPI_ID0:
				frame_phase = SW_FRM_END_ID0(intstat);
				intstat &= ~DVP_ALL_END_ID0;
				break;
			case RKCIF_STREAM_MIPI_ID1:
				frame_phase = SW_FRM_END_ID1(intstat);
				intstat &= ~DVP_ALL_END_ID1;
				break;
			case RKCIF_STREAM_MIPI_ID2:
				frame_phase = SW_FRM_END_ID2(intstat);
				intstat &= ~DVP_ALL_END_ID2;
				break;
			case RKCIF_STREAM_MIPI_ID3:
				frame_phase = SW_FRM_END_ID3(intstat);
				intstat &= ~DVP_ALL_END_ID3;
				break;
			}

			if (frame_phase & CIF_F0_READY)
				frame_ready = 0;
			else
				frame_ready = 1;

			addr = cif->active[frame_ready];
			if (vehicle_cif_next_buffer(cif, frame_ready, ch_id) < 0)
				VEHICLE_DGERR("cif_nex_buffer error, do not commit %lx\n", addr);
			else
				vehicle_flinger_commit_cif_buffer(addr);

			cif->frame_idx++;
		}
	}
	cif->irqinfo.all_frm_end_cnt++;

IRQ_EXIT:
	return IRQ_HANDLED;
}

#define vehicle_csi2_err_strncat(dst_str, src_str) {\
	if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\
		strncat(dst_str, src_str, strlen(src_str)); }

static void vehicle_csi2_find_err_vc(int val, char *vc_info)
{
	int i;
	char cur_str[CSI_VCINFO_LEN] = {0};

	memset(vc_info, 0, sizeof(*vc_info));
	for (i = 0; i < 4; i++) {
		if ((val >> i) & 0x1) {
			snprintf(cur_str, CSI_VCINFO_LEN, " %d", i);
			if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN)
				strncat(vc_info, cur_str, strlen(cur_str));
		}
	}
}

static void vehicle_csi2_err_print_work(struct work_struct *work)
{
	struct vehicle_csi2_err_state_work *err_state = container_of(work,
							struct vehicle_csi2_err_state_work,
							work);

	pr_err("mipi_csi2: ERR%d:0x%x %s\n", err_state->err_num,
		err_state->err_val, err_state->err_str);
	if (err_state->err_num == 1)
		pr_info("mipi_csi2: err_stat:0x%lx\n", err_state->err_stat);
}

static irqreturn_t vehicle_csirx_irq1(int irq, void *data)
{
	struct vehicle_cif *cif = (struct vehicle_cif *)data;
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	struct csi2_err_stats *err_list = NULL;
	unsigned long err_stat = 0;
	u32 val;
	char err_str[CSI_ERRSTR_LEN] = {0};
	char cur_str[CSI_ERRSTR_LEN] = {0};
	char vc_info[CSI_VCINFO_LEN] = {0};

	val = read_reg(hw->csi2_base, CSIHOST_ERR1);
	if (val) {
		write_reg(hw->csi2_base,
				  CSIHOST_ERR1, 0x0);

		if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) {
			err_list = &hw->err_list[RK_CSI2_ERR_SOTSYN];
			err_list->cnt++;

			vehicle_csi2_find_err_vc(val & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}

		if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) {
			err_list = &hw->err_list[RK_CSI2_ERR_FS_FE_MIS];
			err_list->cnt++;
			vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe miss,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);

		}

		if (val & CSIHOST_ERR1_ERR_SEQ) {
			err_list = &hw->err_list[RK_CSI2_ERR_FRM_SEQ_ERR];
			err_list->cnt++;
			vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);

		}

		if (val & CSIHOST_ERR1_ERR_FRM_DATA) {
			err_list = &hw->err_list[RK_CSI2_ERR_CRC_ONCE];
			err_list->cnt++;
			vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);

		}

		if (val & CSIHOST_ERR1_ERR_CRC) {
			err_list = &hw->err_list[RK_CSI2_ERR_CRC];
			err_list->cnt++;
			vehicle_csi2_find_err_vc((val >> 24) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);

		}

		if (val & CSIHOST_ERR1_ERR_ECC2) {
			err_list = &hw->err_list[RK_CSI2_ERR_CRC];
			err_list->cnt++;
			snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) ");
			vehicle_csi2_err_strncat(err_str, cur_str);

		}
		if (val & CSIHOST_ERR1_ERR_CTRL) {
			vehicle_csi2_find_err_vc((val >> 16) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		hw->err_list[RK_CSI2_ERR_ALL].cnt++;
		err_stat = ((hw->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
			    ((hw->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);

		cif->err_state.err_val = val;
		cif->err_state.err_num = 1;
		cif->err_state.err_stat = err_stat;
		strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN);
		queue_work(cif->err_state.err_print_wq, &cif->err_state.work);

	}

	return IRQ_HANDLED;
}

static irqreturn_t vehicle_csirx_irq2(int irq, void *data)
{
	struct vehicle_cif *cif = (struct vehicle_cif *)data;
	struct csi2_dphy_hw *hw = cif->dphy_hw;
	u32 val;
	char cur_str[CSI_ERRSTR_LEN] = {0};
	char err_str[CSI_ERRSTR_LEN] = {0};
	char vc_info[CSI_VCINFO_LEN] = {0};

	val = read_reg(hw->csi2_base, CSIHOST_ERR2);
	if (val) {
		if (val & CSIHOST_ERR2_PHYERR_ESC) {
			vehicle_csi2_find_err_vc(val & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		if (val & CSIHOST_ERR2_PHYERR_SOTHS) {
			vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		if (val & CSIHOST_ERR2_ECC_CORRECTED) {
			vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		if (val & CSIHOST_ERR2_ERR_ID) {
			vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info);
			snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info);
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		if (val & CSIHOST_ERR2_PHYERR_CODEHS) {
			snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) ");
			vehicle_csi2_err_strncat(err_str, cur_str);
		}
		cif->err_state.err_val = val;
		cif->err_state.err_num = 2;
		strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN);
		queue_work(cif->err_state.err_print_wq, &cif->err_state.work);

	}

	return IRQ_HANDLED;
}

int vehicle_cif_reverse_open(struct vehicle_cfg *v_cfg)
{
	int ret = 0;
	struct vehicle_cif *cif = g_cif;

	if (!cif)
		return -ENODEV;

	mutex_lock(&cif->stream_lock);
	memcpy(&cif->cif_cfg, v_cfg, sizeof(struct vehicle_cfg));
	ret = pm_runtime_get_sync(cif->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(cif->dev);
		VEHICLE_DGERR("%s pm_runtime_get_sync failed\n", __func__);
		goto exit;
	}

	/*get dcphy param*/
	if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) {
		if (cif->cif_cfg.dphy_param) {
			cif->dphy_hw->dphy_param = cif->cif_cfg.dphy_param;
			dev_info(cif->dev, "-----get dphy param from sensor----\n");
		} else {
			cif->dphy_hw->dphy_param = &rk3588_dcphy_param;
			dev_info(cif->dev, "fail to get dphy param, used default value\n");
		}
	}
	/* set ddr fix freq */
	rockchip_set_system_status(SYS_STATUS_CIF0);
	vehicle_cif_hw_soft_reset(cif);
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		/* 0. set mipi-dphy data rate */
		cif->dphy_hw->data_rate_mbps = cif->cif_cfg.mipi_freq * 2 / 1000 / 1000;

		/* 0. set csi2 & dphy clk */
		vehicle_csi2_hw_soft_reset(cif);
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 ||
			cif->dphy_hw->chip_id >= CHIP_ID_RK3562)
			vehicle_csi2_dphy_hw_do_reset(cif);

		if (!cif->dphy_hw->on)
			vehicle_csi2_clk_ctrl(cif, 1);

		/*  1. stream setup */
		cif_csi_stream_setup(cif);

		/*  2. create dummy buf */
		ret = vehicle_cif_create_dummy_buf(cif);
		if (ret < 0)
			VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret);

		/*  3. cif init buffer */
		if (vehicle_cif_init_buffer(cif, 1, cif->channels[0].id) < 0)
			goto exit;

		/*  4. dump cif regs */
		vehicle_cif_csi2_dump_regs(cif);

		/*  5. start stream */
		if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF)
			vehicle_cif_csi2_s_stream_v1(cif, 1, V4L2_MBUS_CSI2_DPHY);
		else
			vehicle_cif_csi2_s_stream(cif, 1, V4L2_MBUS_CSI2_DPHY);

	} else {
		/*  1. stream setup */
		cif_stream_setup(cif);

		/*  2. create dummy buf */
		ret = vehicle_cif_create_dummy_buf(cif);
		if (ret < 0)
			VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret);

		/*  2. cif init buffer */
		if (vehicle_cif_init_buffer(cif, 1, 0) < 0)
			goto exit;

		/*  3. enable interrupts */
		if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF)
			cif_interrupt_setup(cif);

		/*  4. dump cif regs */
		vehicle_cif_dvp_dump_regs(cif);

		/*  5. start stream */
		vehicle_cif_s_stream(cif, 1);
	}

	cif->stopping = false;
	drop_frames_number = cif->drop_frames;

	mutex_unlock(&cif->stream_lock);

	return 0;

exit:
	mutex_unlock(&cif->stream_lock);
	return -1;
}

int vehicle_cif_reverse_close(void)
{
	int ret = 0;
	struct vehicle_cif *cif = g_cif;

	if (!cif)
		return -ENODEV;

	mutex_lock(&cif->stream_lock);

	VEHICLE_DG("%s cif reverse start closing\n", __func__);
	cif->stopping = true;
	cancel_delayed_work_sync(&(cif->work));
	flush_delayed_work(&(cif->work));
	cancel_work_sync(&cif->err_state.work);

	ret = wait_event_timeout(cif->wq_stopped,
				 cif->state != RKCIF_STATE_STREAMING,
				 msecs_to_jiffies(100));
	if (!ret) {
		VEHICLE_DGERR("%s wait stream stop timeout!\n", __func__);
		if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
			if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF)
				vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY);
			else
				vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY);
		} else {
			vehicle_cif_s_stream(cif, 0);
		}
		//cif->stopping = false;
	}
	if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		vehicle_cif_csi_stream_stop(cif);
		vehicle_csi2_hw_soft_reset(cif);
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 ||
			cif->dphy_hw->chip_id >= CHIP_ID_RK3562)
			vehicle_csi2_dphy_hw_do_reset(cif);
		if (cif->dphy_hw->on)
			vehicle_csi2_clk_ctrl(cif, 0);
	}

	vehicle_cif_destroy_dummy_buf(cif);
	//vehicle_csi2_hw_soft_reset(cif);
	//vehicle_cif_hw_soft_reset(cif);
	rockchip_clear_system_status(SYS_STATUS_CIF0);
	mutex_unlock(&cif->stream_lock);
	cif->stopping = false;

	return 0;
}

static int cif_parse_dt(struct vehicle_cif *cif)
{
	struct device *dev = cif->dev;
	struct device_node *node;
	struct device_node *phy_node;
	struct device_node *cif_node;
	struct device_node *cis2_node;
	const char *status = NULL;

	if (of_property_read_u32(dev->of_node, "cif,drop-frames",
				 &cif->drop_frames)) {
		VEHICLE_INFO("%s:Get cif, drop-frames failed!\n", __func__);
		cif->drop_frames = 0; //default drop frames;
	}

	if (of_property_read_u32(dev->of_node, "cif,chip-id",
				 &cif->chip_id)) {
		VEHICLE_INFO("%s:Get cif, chip_id failed!\n", __func__);
		cif->chip_id = CHIP_RK3588_VEHICLE_CIF; //default rk3588;
	}

	cif_node = of_parse_phandle(dev->of_node, "rockchip,cif", 0);
	cif->base = (char *)of_iomap(cif_node, 0);

	node = of_parse_phandle(dev->of_node, "rockchip,cru", 0);
	cif->cru_base = of_iomap(node, 0);
	of_node_put(node);

	node = of_parse_phandle(dev->of_node, "rockchip,grf", 0);
	cif->grf_base = of_iomap(node, 0);
	of_node_put(node);

	cif->regmap_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
	if (IS_ERR(cif->regmap_grf))
		VEHICLE_DGERR("unable to get rockchip,grf\n");

	cif->irq = irq_of_parse_and_map(cif_node, 0);
	of_node_put(cif_node);
	if (cif->irq < 0) {
		VEHICLE_DGERR("%s: request cif irq failed\n", __func__);
		goto unmap_cif;
	}

	node = of_parse_phandle(dev->of_node, "rockchip,cif-phy", 0);
	if (!node) {
		VEHICLE_DGERR("get cif-phy dts failed\n");
		goto unmap_cif;
	}

	for_each_child_of_node(node, phy_node) {
		of_property_read_string(phy_node, "status", &status);
		if (status && !strcmp(status, "disabled"))
			continue;
		else
			cif->phy_node = phy_node;
		VEHICLE_INFO("status: %s %s\n", cif->phy_node->name, status);
	}
	of_node_put(node);
	if (of_property_read_u32(cif->phy_node, "csihost-idx", &cif->csi_host_idx)) {
		VEHICLE_INFO("Get %s csihost-idx failed! sensor link to dvp!!\n",
				cif->phy_node->name);
		cif->inf_id = RKCIF_DVP;
	} else {
		cif->inf_id = RKCIF_MIPI_LVDS;
		VEHICLE_INFO("sensor link to %s!!\n", cif->phy_node->name);
	}

	if (cif->inf_id == RKCIF_MIPI_LVDS) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF &&
		    !(cif->csi_host_idx == RKCIF_MIPI0_CSI2 ||
		      cif->csi_host_idx == RKCIF_MIPI1_CSI2)) {
			node = of_parse_phandle(cif->phy_node, "rockchip,csi2-dphy", 0);
			cif->csi2_dphy_base = of_iomap(node, 0);
			of_node_put(node);

			cif->regmap_dphy_grf =
				syscon_regmap_lookup_by_phandle(cif->phy_node, "rockchip,dphy-grf");
			if (IS_ERR(cif->regmap_dphy_grf))
				VEHICLE_INFO("unable to get rockchip,dphy-grf\n");
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF &&
			cif->csi_host_idx != RKCIF_MIPI0_CSI2) {
			node = of_parse_phandle(cif->phy_node, "rockchip,csi2-dphy", 0);
			cif->csi2_dphy_base = of_iomap(node, 0);
			of_node_put(node);

			cif->regmap_dphy_grf =
				syscon_regmap_lookup_by_phandle(cif->phy_node, "rockchip,dphy-grf");
			if (IS_ERR(cif->regmap_dphy_grf))
				VEHICLE_INFO("unable to get rockchip,dphy-grf\n");

			cif->dphy_sys_grf =
				syscon_regmap_lookup_by_phandle(cif->phy_node, "rockchip,sys-grf");
			if (IS_ERR(cif->dphy_sys_grf))
				VEHICLE_INFO("unable to get rockchip,sys-grf\n");
		} else if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF &&
				cif->chip_id != CHIP_RK3576_VEHICLE_CIF) {
			node = of_parse_phandle(cif->phy_node, "rockchip,csi2-dphy", 0);
			cif->csi2_dphy_base = of_iomap(node, 0);
			of_node_put(node);
		}

		cis2_node = of_parse_phandle(cif->phy_node, "rockchip,csi2", 0);
		cif->csi2_base = of_iomap(cis2_node, 0);

		cif->csi2_irq1 = irq_of_parse_and_map(cis2_node, 0);
		if (cif->csi2_irq1 < 0) {
			VEHICLE_DGERR("%s: request csi-intr1 failed\n", __func__);
			of_node_put(cis2_node);
			goto unmap_csi;
		}

		cif->csi2_irq2 = irq_of_parse_and_map(cis2_node, 1);
		of_node_put(cis2_node);
		if (cif->csi2_irq2 < 0) {
			VEHICLE_DGERR("%s: request csi-intr2 failed\n", __func__);
			goto unmap_csi;
		}
	}

	VEHICLE_DG("%s, drop_frames = %d\n", __func__, cif->drop_frames);

	return 0;

unmap_csi:
	iounmap(cif->csi2_dphy_base);
	iounmap(cif->csi2_base);
unmap_cif:
	iounmap(cif->base);
	iounmap(cif->cru_base);
	iounmap(cif->grf_base);

	return -ENODEV;
}

int vehicle_cif_init(struct vehicle_cif *cif)
{
	int ret;
	struct device *dev;
	struct rk_cif_clk *clk;
	struct csi2_dphy_hw *dphy_hw;
	struct clk *tmp_cif_clk = NULL;
	int i;
	int inf_id;

	if (!cif)
		return -ENODEV;

	dev = cif->dev;
	clk = &cif->clk;
	g_cif = cif;

	/* 0. dts parse */
	if (cif_parse_dt(cif) < -1) {
		VEHICLE_DGERR("%s: cif_parse_dt failed\n", __func__);
		return -ENODEV;
	}

	inf_id = cif->inf_id;
	if (inf_id == RKCIF_MIPI_LVDS) {
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			if (cif->csi_host_idx == RKCIF_MIPI0_CSI2 ||
			    cif->csi_host_idx == RKCIF_MIPI1_CSI2)
				dphy_hw = &rk3588_csi2_dcphy_hw;
			else
				dphy_hw = &rk3588_csi2_dphy_hw;
		} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
			dphy_hw = &rk3562_csi2_dphy_hw;
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->csi_host_idx == RKCIF_MIPI0_CSI2)
				dphy_hw = &rk3576_csi2_dcphy_hw;
			else
				dphy_hw = &rk3576_csi2_dphy_hw;
		} else {
			dphy_hw = &rk3568_csi2_dphy_hw;
		}
	}

	/*  1. cif/csi2-dphy/csi2 clk setup */
	if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
		clk->clks_num = ARRAY_SIZE(rk3588_cif_clks);
		clk->rsts_num = ARRAY_SIZE(rk3588_cif_rsts);
	} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
		clk->clks_num = ARRAY_SIZE(rk3562_cif_clks);
		clk->rsts_num = ARRAY_SIZE(rk3562_cif_rsts);
	} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
		clk->clks_num = ARRAY_SIZE(rk3576_cif_clks);
		clk->rsts_num = ARRAY_SIZE(rk3576_cif_rsts);
	} else {
		clk->clks_num = ARRAY_SIZE(rk3568_cif_clks);
		clk->rsts_num = ARRAY_SIZE(rk3568_cif_rsts);
	}

	if (inf_id == RKCIF_MIPI_LVDS) {
		cif->dphy_hw = dphy_hw;
		dphy_hw->dev = cif->dev;
		/*get phy_index*/
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) {
			if (cif->csi_host_idx >= RKCIF_MIPI4_CSI2)
				cif->dphy_hw->phy_index = 3;
			else
				cif->dphy_hw->phy_index = 0;
		} else if (cif->dphy_hw->chip_id == CHIP_ID_RK3562) {
			if (cif->csi_host_idx >= RKCIF_MIPI2_CSI2)
				cif->dphy_hw->phy_index = 3;
			else
				cif->dphy_hw->phy_index = 0;
		} else if (cif->dphy_hw->chip_id == CHIP_ID_RK3576) {
			if (cif->csi_host_idx >= RKCIF_MIPI3_CSI2)
				cif->dphy_hw->phy_index = 3;
			else
				cif->dphy_hw->phy_index = 0;
		} else {
			cif->dphy_hw->phy_index = 0;
		}
		/*get mipi dcphy*/
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) {
			struct phy *dcphy = NULL;
			struct samsung_mipi_dcphy *dcphy_hw = NULL;

			dcphy = of_phy_get(cif->phy_node, "dcphy");
			if (IS_ERR(dcphy)) {
				ret = PTR_ERR(dcphy);
				dev_err(dev, "failed to get mipi dcphy: %d\n", ret);
				return ret;
			}
			dcphy_hw = phy_get_drvdata(dcphy);
			dcphy_hw->dphy_vehicle[dcphy_hw->dphy_vehicle_num] = cif->dphy_hw;
			dcphy_hw->dphy_vehicle_num++;
			cif->dphy_hw->samsung_phy = dcphy_hw;
		}
		/* csi2 mipidphy rsts */
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3562 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3576) {
			for (i = 0; i < dphy_hw->num_dphy_rsts; i++) {
				struct reset_control *rst = NULL;

				rst = of_reset_control_get(cif->phy_node, dphy_hw->dphy_rsts[i]);
				if (IS_ERR(rst)) {
					dev_err(dev, "failed to get %s\n", dphy_hw->dphy_rsts[i]);
					return PTR_ERR(rst);
				}
				dphy_hw->dphy_rst[i] = rst;
			}
		} else {
			dev_info(dev, "use mipi dcphy, no need request rst\n");
		}

		/* csi2 mipidphy clks */
		for (i = 0; i < dphy_hw->num_dphy_clks; i++) {
			struct clk *tmp_clk =
				of_clk_get_by_name(cif->phy_node, dphy_hw->dphy_clks[i].id);

			if (IS_ERR(tmp_clk)) {
				dev_err(dev, "failed to get %s\n", dphy_hw->dphy_clks[i].id);
				return PTR_ERR(tmp_clk);
			}
			dev_info(dev, "clk get %s\n", dphy_hw->dphy_clks[i].id);
			dphy_hw->dphy_clks[i].clk = tmp_clk;
		}

		/* csi2 clks */
		for (i = 0; i < dphy_hw->num_csi2_clks; i++) {
			struct clk *tmp_clk =
				of_clk_get_by_name(cif->phy_node, dphy_hw->csi2_clks[i].id);

			if (IS_ERR(tmp_clk)) {
				dev_err(dev, "failed to get %s\n", dphy_hw->csi2_clks[i].id);
				return PTR_ERR(tmp_clk);
			}
			dev_info(dev, "clk get %s\n", dphy_hw->csi2_clks[i].id);
			dphy_hw->csi2_clks[i].clk = tmp_clk;
		}

		/* csi2 rsts */
		for (i = 0; i < dphy_hw->num_csi2_rsts; i++) {
			struct reset_control *rst = NULL;

			rst = of_reset_control_get(cif->phy_node, dphy_hw->csi2_rsts[i]);
			if (IS_ERR(rst)) {
				dev_err(dev, "failed to get %s\n", dphy_hw->csi2_rsts[i]);
				return PTR_ERR(rst);
			}
			dphy_hw->csi2_rst[i] = rst;
		}
		dphy_hw->on = false;
	}
	/* vicap clks */
	if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
		for (i = 0; i < clk->clks_num; i++) {
			tmp_cif_clk = devm_clk_get(dev, rk3588_cif_clks[i]);

			if (IS_ERR(tmp_cif_clk)) {
				dev_err(dev, "failed to get %s\n", rk3588_cif_clks[i]);
				return PTR_ERR(tmp_cif_clk);
			}
			clk->clks[i] = tmp_cif_clk;
			clk->on = false;
		}
	} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
		for (i = 0; i < clk->clks_num; i++) {
			tmp_cif_clk = devm_clk_get(dev, rk3562_cif_clks[i]);

			if (IS_ERR(tmp_cif_clk)) {
				dev_err(dev, "failed to get %s\n", rk3562_cif_clks[i]);
				return PTR_ERR(tmp_cif_clk);
			}
			clk->clks[i] = tmp_cif_clk;
			clk->on = false;
		}
	} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
		for (i = 0; i < clk->clks_num; i++) {
			tmp_cif_clk = devm_clk_get(dev, rk3576_cif_clks[i]);

			if (IS_ERR(tmp_cif_clk)) {
				dev_err(dev, "failed to get %s\n", rk3576_cif_clks[i]);
				return PTR_ERR(tmp_cif_clk);
			}
			clk->clks[i] = tmp_cif_clk;
			clk->on = false;
		}
	} else {
		for (i = 0; i < clk->clks_num; i++) {
			tmp_cif_clk = devm_clk_get(dev, rk3568_cif_clks[i]);

			if (IS_ERR(tmp_cif_clk)) {
				dev_err(dev, "failed to get %s\n", rk3568_cif_clks[i]);
				return PTR_ERR(tmp_cif_clk);
			}
			clk->clks[i] = tmp_cif_clk;
			clk->on = false;
		}
	}

	/* vicap rsts */
	if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
		for (i = 0; i < clk->rsts_num; i++) {
			struct reset_control *rst = NULL;

			if (rk3588_cif_rsts[i])
				rst = devm_reset_control_get(dev, rk3588_cif_rsts[i]);
			if (IS_ERR(rst)) {
				dev_err(dev, "failed to get %s\n", rk3588_cif_rsts[i]);
				return PTR_ERR(rst);
			}
			clk->cif_rst[i] = rst;
		}
	} else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) {
		for (i = 0; i < clk->rsts_num; i++) {
			struct reset_control *rst = NULL;

			if (rk3562_cif_rsts[i])
				rst = devm_reset_control_get(dev, rk3562_cif_rsts[i]);
			if (IS_ERR(rst)) {
				dev_err(dev, "failed to get %s\n", rk3562_cif_rsts[i]);
				return PTR_ERR(rst);
			}
			clk->cif_rst[i] = rst;
		}
	} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
		for (i = 0; i < clk->rsts_num; i++) {
			struct reset_control *rst = NULL;

			if (rk3576_cif_rsts[i])
				rst = devm_reset_control_get(dev, rk3576_cif_rsts[i]);
			if (IS_ERR(rst)) {
				dev_err(dev, "failed to get %s\n", rk3576_cif_rsts[i]);
				return PTR_ERR(rst);
			}
			clk->cif_rst[i] = rst;
		}
	} else {
		for (i = 0; i < clk->rsts_num; i++) {
			struct reset_control *rst = NULL;

			if (rk3568_cif_rsts[i])
				rst = devm_reset_control_get(dev, rk3568_cif_rsts[i]);
			if (IS_ERR(rst)) {
				dev_err(dev, "failed to get %s\n", rk3568_cif_rsts[i]);
				return PTR_ERR(rst);
			}
			clk->cif_rst[i] = rst;
		}
	}

	/*  2. set cif clk & sensor mclk */
	rk_cif_mclk_ctrl(cif, 1);
	INIT_DELAYED_WORK(&cif->work, vehicle_cif_reset_work_func);

	if (inf_id == RKCIF_MIPI_LVDS)
		/*  2. set csi2 & dphy clk */
		if (!cif->dphy_hw->on)
			vehicle_csi2_clk_ctrl(cif, 1);

	/*  3. request cif irq & mipi csi irq1-2 */
	if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) {
		ret = devm_request_irq(dev, cif->irq,
				rk_camera_irq_v1, IRQF_SHARED, "vehicle_cif", cif);
		if (ret < 0) {
			VEHICLE_DGERR("request cif irq failed!\n");
			return -EINVAL;
		}
	} else {
		ret = devm_request_irq(dev, cif->irq,
				rk_camera_irq, IRQF_SHARED, "vehicle_cif", cif);
		if (ret < 0) {
			VEHICLE_DGERR("request cif irq failed!\n");
			return -EINVAL;
		}
	}

	VEHICLE_DG("%s(%d):\n", __func__, __LINE__);

	if (inf_id == RKCIF_MIPI_LVDS) {
		ret = devm_request_irq(dev, cif->csi2_irq1, vehicle_csirx_irq1,
				IRQF_SHARED, "vehicle_csi_intr1", cif);
		if (ret < 0) {
			VEHICLE_DGERR("request csirx irq1 failed!\n");
			return -EINVAL;
		}

		ret = devm_request_irq(dev, cif->csi2_irq2, vehicle_csirx_irq2,
				IRQF_SHARED, "vehicle_csi_intr2", cif);
		if (ret < 0) {
			VEHICLE_DGERR("request csirx irq2 failed!\n");
			return -EINVAL;
		}
	}
	/*  4. set cif regs */
	if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF)
		cif->cif_regs = rk3588_cif_regs;
	else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF)
		cif->cif_regs = rk3562_cif_regs;
	else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF)
		cif->cif_regs = rk3576_cif_regs;
	else
		cif->cif_regs = rk3568_cif_regs;

	if (inf_id == RKCIF_MIPI_LVDS) {
		/* 5. set csi2-mipi-dphy reg */
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3568 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3562 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3576)
			cif->dphy_hw->csi2_dphy_base = cif->csi2_dphy_base;

		/* 7. set mipi-csi2 reg */
		cif->dphy_hw->csi2_base = cif->csi2_base;

		/* 8. set dphy grf regmap */
		if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) {
			if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) {
				cif->dphy_hw->regmap_grf = cif->regmap_dphy_grf;
				cif->dphy_hw->regmap_sys_grf = cif->regmap_grf;
			}
		} else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) {
			if (cif->dphy_hw->chip_id == CHIP_ID_RK3576) {
				cif->dphy_hw->regmap_grf = cif->regmap_dphy_grf;
				cif->dphy_hw->regmap_sys_grf = cif->dphy_sys_grf;
			}
		} else {
			cif->dphy_hw->regmap_grf = cif->regmap_grf;
		}
		mutex_init(&dphy_hw->mutex);
	}

	if (cif->inf_id == RKCIF_MIPI_LVDS && cif->chip_id <= CHIP_RK3562_VEHICLE_CIF)
		cif->use_hw_interlace = false;
	else
		cif->use_hw_interlace = true;

	/* 9. init waitqueue */
	atomic_set(&cif->reset_status, 0);
	init_waitqueue_head(&cif->wq_stopped);

	spin_lock_init(&cif->vbq_lock);

	INIT_WORK(&cif->err_state.work, vehicle_csi2_err_print_work);
	cif->err_state.err_print_wq = create_workqueue("cis2_err_print_queue");
	if (cif->err_state.err_print_wq == NULL) {
		dev_err(dev, "%s: %s create failed.\n", __func__,
			"csi2_err_print_wq");
	}

	return 0;
}

int vehicle_cif_deinit(struct vehicle_cif *cif)
{
	struct rk_cif_clk *clk = &cif->clk;
	struct device *dev = cif->dev;
	int i;
	struct csi2_dphy_hw *dphy_hw = cif->dphy_hw;
	int inf_id = cif->inf_id;

	// vehicle_cif_s_stream(cif, 0);
	// vehicle_cif_do_stop_stream(cif);

	/* set csi2-dphy csi cif clk */
	rk_cif_mclk_ctrl(cif, 0);
	if (inf_id == RKCIF_MIPI_LVDS)
		if (cif->dphy_hw->on)
			vehicle_csi2_clk_ctrl(cif, 0);

	/* vicap rsts release */
	for (i = 0; i < clk->rsts_num; i++)
		reset_control_put(clk->cif_rst[i]);

	/* vicap clk release */
	for (i = 0; i < clk->clks_num; i++)
		devm_clk_put(dev, clk->clks[i]);

	if (inf_id == RKCIF_MIPI_LVDS) {
		/*dcphy put*/
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) {
			struct samsung_mipi_dcphy *dcphy_hw = cif->dphy_hw->samsung_phy;
			struct csi2_dphy_hw *csi2_dphy = NULL;

			for (i = 0; i < dcphy_hw->dphy_vehicle_num; i++) {
				csi2_dphy = dcphy_hw->dphy_vehicle[i];
				if (csi2_dphy) {
					dcphy_hw->dphy_vehicle[i] = NULL;
					dcphy_hw->dphy_vehicle_num--;
					break;
				}
			}
		}
		/* dphy clks release */
		for (i = 0; i < dphy_hw->num_dphy_clks; i++)
			clk_put(dphy_hw->dphy_clks[i].clk);
		/* dphy rsts release */
		if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3562 ||
		    cif->dphy_hw->chip_id == CHIP_ID_RK3576) {
			for (i = 0; i < dphy_hw->num_dphy_rsts; i++)
				reset_control_put(dphy_hw->dphy_rst[i]);
		}
		/* csi2 clks release */
		for (i = 0; i < dphy_hw->num_csi2_clks; i++)
			clk_put(dphy_hw->csi2_clks[i].clk);
		/* csi2 resets release */
		for (i = 0; i < dphy_hw->num_csi2_rsts; i++)
			reset_control_put(dphy_hw->csi2_rst[i]);

		mutex_destroy(&dphy_hw->mutex);
	}

	devm_free_irq(dev, cif->irq, cif);
	if (inf_id == RKCIF_MIPI_LVDS) {
		devm_free_irq(dev, cif->csi2_irq1, cif);
		devm_free_irq(dev, cif->csi2_irq2, cif);
	}
	if (cif->err_state.err_print_wq) {
		flush_workqueue(cif->err_state.err_print_wq);
		destroy_workqueue(cif->err_state.err_print_wq);
	}

	return 0;
}
